diff --git a/.gitignore b/.gitignore index 1709fa6..964f6e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -session.json # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -104,6 +103,7 @@ celerybeat.pid # Environments .env +.envrc .venv env/ venv/ @@ -128,3 +128,4 @@ dmypy.json # Pyre type checker .pyre/ + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9b38853 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4277ddc --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +PATH := ./venv/bin:${PATH} +sources = garminconnect tests setup.py + +.PHONY: .venv ## Install virtual environment +.venv: + python -m venv .venv + python -m pip install -qU pip + +.PHONY: install ## Install package +install: .venv + pip install -qUe . + +.PHONY: install-test ## Install package in development mode +install-test: .venv install + pip install -qU -r requirements-test.txt + +.PHONY: test ## Run tests +test: + pytest --cov=garminconnect --cov-report=term-missing \ No newline at end of file diff --git a/README.md b/README.md index 4b9b324..5279d66 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/cyberjunkynl/) - # Python: Garmin Connect +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/cyberjunkynl/) + Python 3 API wrapper for Garmin Connect to get your statistics. ## About @@ -12,562 +12,22 @@ See ## Installation ```bash -pip3 install garminconnect +python -m pip install garminconnect ``` -## API Demo Program - -I wrote this for testing and playing with all available/known API calls. -If you run it from the python-garmin connect directory it will use the library code beneath it, so you can develop without reinstalling the package. +## Authentication -The code also demonstrates how to implement session saving and re-using of the cookies. +The library uses the same authentication method as the app using [Garth](https://github.com/matin/garth). +The login credentials generated with Garth are valid for a year to avoid needing to login each time. -You can set environment variables with your credentials like so, this is optional: +## Testing ```bash -export EMAIL= -export PASSWORD= -``` - -Install the pre-requisites for the example program (not all are needed for using the library package): - -```bash -pip3 install cloudscraper readchar requests pwinput -``` - -Or you can just run the program and enter your credentials when asked, it will create and save a session file and use that until it's outdated/invalid. - -``` -python3 ./example.py -*** Garmin Connect API Demo by cyberjunky *** - -1 -- Get full name -2 -- Get unit system -3 -- Get activity data for '2023-03-10' -4 -- Get activity data for '2023-03-10' (compatible with garminconnect-ha) -5 -- Get body composition data for '2023-03-10' (compatible with garminconnect-ha) -6 -- Get body composition data for from '2023-03-03' to '2023-03-10' (to be compatible with garminconnect-ha) -7 -- Get stats and body composition data for '2023-03-10' -8 -- Get steps data for '2023-03-10' -9 -- Get heart rate data for '2023-03-10' -0 -- Get training readiness data for '2023-03-10' -- -- Get daily step data for '2023-03-03' to '2023-03-10' -/ -- Get body battery data for '2023-03-03' to '2023-03-10' -! -- Get floors data for '2023-03-03' -? -- Get blood pressure data for '2023-03-03' to '2023-03-10' -. -- Get training status data for '2023-03-10' -a -- Get resting heart rate data for 2023-03-10' -b -- Get hydration data for '2023-03-10' -c -- Get sleep data for '2023-03-10' -d -- Get stress data for '2023-03-10' -e -- Get respiration data for '2023-03-10' -f -- Get SpO2 data for '2023-03-10' -g -- Get max metric data (like vo2MaxValue and fitnessAge) for '2023-03-10' -h -- Get personal record for user -i -- Get earned badges for user -j -- Get adhoc challenges data from start '0' and limit '100' -k -- Get available badge challenges data from '1' and limit '100' -l -- Get badge challenges data from '1' and limit '100' -m -- Get non completed badge challenges data from '1' and limit '100' -n -- Get activities data from start '0' and limit '100' -o -- Get last activity -p -- Download activities data by date from '2023-03-03' to '2023-03-10' -r -- Get all kinds of activities data from '0' -s -- Upload activity data from file 'MY_ACTIVITY.fit' -t -- Get all kinds of Garmin device info -u -- Get active goals -v -- Get future goals -w -- Get past goals -y -- Get all Garmin device alarms -x -- Get Heart Rate Variability data (HRV) for '2023-03-10' -z -- Get progress summary from '2023-03-03' to '2023-03-10' for all metrics -A -- Get gear, the defaults, activity types and statistics -Z -- Logout Garmin Connect portal -q -- Exit - -Make your selection: - +make install-test +make test ``` -This is some example code, and probably older than the latest code which can be found in 'example.py'. - -```python -#!/usr/bin/env python3 -""" -pip3 install cloudscraper requests readchar pwinput - -export EMAIL= -export PASSWORD= - -""" -import datetime -import json -import logging -import os -import sys - -import requests -import pwinput -import readchar - -from garminconnect import ( - Garmin, - GarminConnectAuthenticationError, - GarminConnectConnectionError, - GarminConnectTooManyRequestsError, -) - -# Configure debug logging -# logging.basicConfig(level=logging.DEBUG) -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -# Load environment variables if defined -email = os.getenv("EMAIL") -password = os.getenv("PASSWORD") -api = None - -# Example selections and settings -today = datetime.date.today() -startdate = today - datetime.timedelta(days=7) # Select past week -start = 0 -limit = 100 -start_badge = 1 # Badge related calls calls start counting at 1 -activitytype = "" # Possible values are: cycling, running, swimming, multi_sport, fitness_equipment, hiking, walking, other -activityfile = "MY_ACTIVITY.fit" # Supported file types are: .fit .gpx .tcx - -menu_options = { - "1": "Get full name", - "2": "Get unit system", - "3": f"Get activity data for '{today.isoformat()}'", - "4": f"Get activity data for '{today.isoformat()}' (compatible with garminconnect-ha)", - "5": f"Get body composition data for '{today.isoformat()}' (compatible with garminconnect-ha)", - "6": f"Get body composition data for from '{startdate.isoformat()}' to '{today.isoformat()}' (to be compatible with garminconnect-ha)", - "7": f"Get stats and body composition data for '{today.isoformat()}'", - "8": f"Get steps data for '{today.isoformat()}'", - "9": f"Get heart rate data for '{today.isoformat()}'", - "0": f"Get training readiness data for '{today.isoformat()}'", - "-": f"Get daily step data for '{startdate.isoformat()}' to '{today.isoformat()}'", - "/": f"Get body battery data for '{startdate.isoformat()}' to '{today.isoformat()}'", - "!": f"Get floors data for '{startdate.isoformat()}'", - "?": f"Get blood pressure data for '{startdate.isoformat()}' to '{today.isoformat()}'", - ".": f"Get training status data for '{today.isoformat()}'", - "a": f"Get resting heart rate data for {today.isoformat()}'", - "b": f"Get hydration data for '{today.isoformat()}'", - "c": f"Get sleep data for '{today.isoformat()}'", - "d": f"Get stress data for '{today.isoformat()}'", - "e": f"Get respiration data for '{today.isoformat()}'", - "f": f"Get SpO2 data for '{today.isoformat()}'", - "g": f"Get max metric data (like vo2MaxValue and fitnessAge) for '{today.isoformat()}'", - "h": "Get personal record for user", - "i": "Get earned badges for user", - "j": f"Get adhoc challenges data from start '{start}' and limit '{limit}'", - "k": f"Get available badge challenges data from '{start_badge}' and limit '{limit}'", - "l": f"Get badge challenges data from '{start_badge}' and limit '{limit}'", - "m": f"Get non completed badge challenges data from '{start_badge}' and limit '{limit}'", - "n": f"Get activities data from start '{start}' and limit '{limit}'", - "o": "Get last activity", - "p": f"Download activities data by date from '{startdate.isoformat()}' to '{today.isoformat()}'", - "r": f"Get all kinds of activities data from '{start}'", - "s": f"Upload activity data from file '{activityfile}'", - "t": "Get all kinds of Garmin device info", - "u": "Get active goals", - "v": "Get future goals", - "w": "Get past goals", - "y": "Get all Garmin device alarms", - "x": f"Get Heart Rate Variability data (HRV) for '{today.isoformat()}'", - "z": f"Get progress summary from '{startdate.isoformat()}' to '{today.isoformat()}' for all metrics", - "A": "Get gear, the defaults, activity types and statistics", - "Z": "Logout Garmin Connect portal", - "q": "Exit", -} - -def display_json(api_call, output): - """Format API output for better readability.""" - - dashed = "-"*20 - header = f"{dashed} {api_call} {dashed}" - footer = "-"*len(header) - - print(header) - print(json.dumps(output, indent=4)) - print(footer) - -def display_text(output): - """Format API output for better readability.""" - - dashed = "-"*60 - header = f"{dashed}" - footer = "-"*len(header) - - print(header) - print(json.dumps(output, indent=4)) - print(footer) - -def get_credentials(): - """Get user credentials.""" - email = input("Login e-mail: ") - password = pwinput.pwinput(prompt='Password: ') - - return email, password - - -def init_api(email, password): - """Initialize Garmin API with your credentials.""" - - try: - ## Try to load the previous session - with open("session.json") as f: - saved_session = json.load(f) - - print( - "Login to Garmin Connect using session loaded from 'session.json'...\n" - ) - - # Use the loaded session for initializing the API (without need for credentials) - api = Garmin(session_data=saved_session) - - # Login using the - api.login() - - except (FileNotFoundError, GarminConnectAuthenticationError): - # Login to Garmin Connect portal with credentials since session is invalid or not present. - print( - "Session file not present or turned invalid, login with your Garmin Connect credentials.\n" - "NOTE: Credentials will not be stored, the session cookies will be stored in 'session.json' for future use.\n" - ) - try: - # Ask for credentials if not set as environment variables - if not email or not password: - email, password = get_credentials() - - api = Garmin(email, password) - api.login() - - # Save session dictionary to json file for future use - with open("session.json", "w", encoding="utf-8") as f: - json.dump(api.session_data, f, ensure_ascii=False, indent=4) - except ( - GarminConnectConnectionError, - GarminConnectAuthenticationError, - GarminConnectTooManyRequestsError, - requests.exceptions.HTTPError, - ) as err: - logger.error("Error occurred during Garmin Connect communication: %s", err) - return None - - return api - - -def print_menu(): - """Print examples menu.""" - for key in menu_options.keys(): - print(f"{key} -- {menu_options[key]}") - print("Make your selection: ", end="", flush=True) - - -def switch(api, i): - """Run selected API call.""" - - # Exit example program - if i == "q": - print("Bye!") - sys.exit() - - # Skip requests if login failed - if api: - try: - print(f"\n\nExecuting: {menu_options[i]}\n") - - # USER BASICS - if i == "1": - # Get full name from profile - display_json("api.get_full_name()", api.get_full_name()) - elif i == "2": - # Get unit system from profile - display_json("api.get_unit_system()", api.get_unit_system()) - - # USER STATISTIC SUMMARIES - elif i == "3": - # Get activity data for 'YYYY-MM-DD' - display_json(f"api.get_stats('{today.isoformat()}')", api.get_stats(today.isoformat())) - elif i == "4": - # Get activity data (to be compatible with garminconnect-ha) - display_json(f"api.get_user_summary('{today.isoformat()}')", api.get_user_summary(today.isoformat())) - elif i == "5": - # Get body composition data for 'YYYY-MM-DD' (to be compatible with garminconnect-ha) - display_json(f"api.get_body_composition('{today.isoformat()}')", api.get_body_composition(today.isoformat())) - elif i == "6": - # Get body composition data for multiple days 'YYYY-MM-DD' (to be compatible with garminconnect-ha) - display_json(f"api.get_body_composition('{startdate.isoformat()}', '{today.isoformat()}')", - api.get_body_composition(startdate.isoformat(), today.isoformat()) - ) - elif i == "7": - # Get stats and body composition data for 'YYYY-MM-DD' - display_json(f"api.get_stats_and_body('{today.isoformat()}')", api.get_stats_and_body(today.isoformat())) - - # USER STATISTICS LOGGED - elif i == "8": - # Get steps data for 'YYYY-MM-DD' - display_json(f"api.get_steps_data('{today.isoformat()}')", api.get_steps_data(today.isoformat())) - elif i == "9": - # Get heart rate data for 'YYYY-MM-DD' - display_json(f"api.get_heart_rates('{today.isoformat()}')", api.get_heart_rates(today.isoformat())) - elif i == "0": - # Get training readiness data for 'YYYY-MM-DD' - display_json(f"api.get_training_readiness('{today.isoformat()}')", api.get_training_readiness(today.isoformat())) - elif i == "/": - # Get daily body battery data for 'YYYY-MM-DD' to 'YYYY-MM-DD' - display_json(f"api.get_body_battery('{startdate.isoformat()}, {today.isoformat()}')", api.get_body_battery(startdate.isoformat(), today.isoformat())) - elif i == "?": - # Get daily blood pressure data for 'YYYY-MM-DD' to 'YYYY-MM-DD' - display_json(f"api.get_blood_pressure('{startdate.isoformat()}, {today.isoformat()}')", api.get_blood_pressure(startdate.isoformat(), today.isoformat())) - elif i == "-": - # Get daily step data for 'YYYY-MM-DD' - display_json(f"api.get_daily_steps('{startdate.isoformat()}, {today.isoformat()}')", api.get_daily_steps(startdate.isoformat(), today.isoformat())) - elif i == "!": - # Get daily floors data for 'YYYY-MM-DD' - display_json(f"api.get_floors('{today.isoformat()}')", api.get_floors(today.isoformat())) - elif i == ".": - # Get training status data for 'YYYY-MM-DD' - display_json(f"api.get_training_status('{today.isoformat()}')", api.get_training_status(today.isoformat())) - elif i == "a": - # Get resting heart rate data for 'YYYY-MM-DD' - display_json(f"api.get_rhr_day('{today.isoformat()}')", api.get_rhr_day(today.isoformat())) - elif i == "b": - # Get hydration data 'YYYY-MM-DD' - display_json(f"api.get_hydration_data('{today.isoformat()}')", api.get_hydration_data(today.isoformat())) - elif i == "c": - # Get sleep data for 'YYYY-MM-DD' - display_json(f"api.get_sleep_data('{today.isoformat()}')", api.get_sleep_data(today.isoformat())) - elif i == "d": - # Get stress data for 'YYYY-MM-DD' - display_json(f"api.get_stress_data('{today.isoformat()}')", api.get_stress_data(today.isoformat())) - elif i == "e": - # Get respiration data for 'YYYY-MM-DD' - display_json(f"api.get_respiration_data('{today.isoformat()}')", api.get_respiration_data(today.isoformat())) - elif i == "f": - # Get SpO2 data for 'YYYY-MM-DD' - display_json(f"api.get_spo2_data('{today.isoformat()}')", api.get_spo2_data(today.isoformat())) - elif i == "g": - # Get max metric data (like vo2MaxValue and fitnessAge) for 'YYYY-MM-DD' - display_json(f"api.get_max_metrics('{today.isoformat()}')", api.get_max_metrics(today.isoformat())) - elif i == "h": - # Get personal record for user - display_json("api.get_personal_record()", api.get_personal_record()) - elif i == "i": - # Get earned badges for user - display_json("api.get_earned_badges()", api.get_earned_badges()) - elif i == "j": - # Get adhoc challenges data from start and limit - display_json( - f"api.get_adhoc_challenges({start},{limit})", api.get_adhoc_challenges(start, limit) - ) # 1=start, 100=limit - elif i == "k": - # Get available badge challenges data from start and limit - display_json( - f"api.get_available_badge_challenges({start_badge}, {limit})", api.get_available_badge_challenges(start_badge, limit) - ) # 1=start, 100=limit - elif i == "l": - # Get badge challenges data from start and limit - display_json( - f"api.get_badge_challenges({start_badge}, {limit})", api.get_badge_challenges(start_badge, limit) - ) # 1=start, 100=limit - elif i == "m": - # Get non completed badge challenges data from start and limit - display_json( - f"api.get_non_completed_badge_challenges({start_badge}, {limit})", api.get_non_completed_badge_challenges(start_badge, limit) - ) # 1=start, 100=limit - - # ACTIVITIES - elif i == "n": - # Get activities data from start and limit - display_json(f"api.get_activities({start}, {limit})", api.get_activities(start, limit)) # 0=start, 1=limit - elif i == "o": - # Get last activity - display_json("api.get_last_activity()", api.get_last_activity()) - elif i == "p": - # Get activities data from startdate 'YYYY-MM-DD' to enddate 'YYYY-MM-DD', with (optional) activitytype - # Possible values are: cycling, running, swimming, multi_sport, fitness_equipment, hiking, walking, other - activities = api.get_activities_by_date( - startdate.isoformat(), today.isoformat(), activitytype - ) - - # Download activities - for activity in activities: - - activity_id = activity["activityId"] - display_text(activity) - - print(f"api.download_activity({activity_id}, dl_fmt=api.ActivityDownloadFormat.GPX)") - gpx_data = api.download_activity( - activity_id, dl_fmt=api.ActivityDownloadFormat.GPX - ) - output_file = f"./{str(activity_id)}.gpx" - with open(output_file, "wb") as fb: - fb.write(gpx_data) - print(f"Activity data downloaded to file {output_file}") - - print(f"api.download_activity({activity_id}, dl_fmt=api.ActivityDownloadFormat.TCX)") - tcx_data = api.download_activity( - activity_id, dl_fmt=api.ActivityDownloadFormat.TCX - ) - output_file = f"./{str(activity_id)}.tcx" - with open(output_file, "wb") as fb: - fb.write(tcx_data) - print(f"Activity data downloaded to file {output_file}") - - print(f"api.download_activity({activity_id}, dl_fmt=api.ActivityDownloadFormat.ORIGINAL)") - zip_data = api.download_activity( - activity_id, dl_fmt=api.ActivityDownloadFormat.ORIGINAL - ) - output_file = f"./{str(activity_id)}.zip" - with open(output_file, "wb") as fb: - fb.write(zip_data) - print(f"Activity data downloaded to file {output_file}") - - print(f"api.download_activity({activity_id}, dl_fmt=api.ActivityDownloadFormat.CSV)") - csv_data = api.download_activity( - activity_id, dl_fmt=api.ActivityDownloadFormat.CSV - ) - output_file = f"./{str(activity_id)}.csv" - with open(output_file, "wb") as fb: - fb.write(csv_data) - print(f"Activity data downloaded to file {output_file}") - - elif i == "r": - # Get activities data from start and limit - activities = api.get_activities(start, limit) # 0=start, 1=limit - - # Get activity splits - first_activity_id = activities[0].get("activityId") - - display_json(f"api.get_activity_splits({first_activity_id})", api.get_activity_splits(first_activity_id)) - - # Get activity split summaries for activity id - display_json(f"api.get_activity_split_summaries({first_activity_id})", api.get_activity_split_summaries(first_activity_id)) - - # Get activity weather data for activity - display_json(f"api.get_activity_weather({first_activity_id})", api.get_activity_weather(first_activity_id)) - - # Get activity hr timezones id - display_json(f"api.get_activity_hr_in_timezones({first_activity_id})", api.get_activity_hr_in_timezones(first_activity_id)) - - # Get activity details for activity id - display_json(f"api.get_activity_details({first_activity_id})", api.get_activity_details(first_activity_id)) - - # Get gear data for activity id - display_json(f"api.get_activity_gear({first_activity_id})", api.get_activity_gear(first_activity_id)) - - # Activity self evaluation data for activity id - display_json(f"api.get_activity_evaluation({first_activity_id})", api.get_activity_evaluation(first_activity_id)) - - # Get exercise sets in case the activity is a strength_training - if activities[0]["activityType"]["typeKey"] == "strength_training": - display_json(f"api.get_activity_exercise_sets({first_activity_id})", api.get_activity_exercise_sets(first_activity_id)) - - elif i == "s": - # Upload activity from file - display_json(f"api.upload_activity({activityfile})", api.upload_activity(activityfile)) - - # DEVICES - elif i == "t": - # Get Garmin devices - devices = api.get_devices() - display_json("api.get_devices()", devices) - - # Get device last used - device_last_used = api.get_device_last_used() - display_json("api.get_device_last_used()", device_last_used) - - # Get settings per device - for device in devices: - device_id = device["deviceId"] - display_json(f"api.get_device_settings({device_id})", api.get_device_settings(device_id)) - - # GOALS - elif i == "u": - # Get active goals - goals = api.get_goals("active") - display_json("api.get_goals(\"active\")", goals) - - elif i == "v": - # Get future goals - goals = api.get_goals("future") - display_json("api.get_goals(\"future\")", goals) - - elif i == "w": - # Get past goals - goals = api.get_goals("past") - display_json("api.get_goals(\"past\")", goals) - - # ALARMS - elif i == "y": - # Get Garmin device alarms - alarms = api.get_device_alarms() - for alarm in alarms: - alarm_id = alarm["alarmId"] - display_json(f"api.get_device_alarms({alarm_id})", alarm) - - elif i == "x": - # Get Heart Rate Variability (hrv) data - display_json(f"api.get_hrv_data({today.isoformat()})", api.get_hrv_data(today.isoformat())) - - elif i == "z": - # Get progress summary - for metric in ["elevationGain", "duration", "distance", "movingDuration"]: - display_json( - f"api.get_progress_summary_between_dates({today.isoformat()})", api.get_progress_summary_between_dates( - startdate.isoformat(), today.isoformat(), metric - )) - - # Gear - elif i == "A": - last_used_device = api.get_device_last_used() - display_json(f"api.get_device_last_used()", last_used_device) - userProfileNumber = last_used_device["userProfileNumber"] - gear = api.get_gear(userProfileNumber) - display_json(f"api.get_gear()", gear) - display_json(f"api.get_gear_defaults()", api.get_gear_defaults(userProfileNumber)) - display_json(f"api.get()", api.get_activity_types()) - for gear in gear: - uuid=gear["uuid"] - name=gear["displayName"] - display_json(f"api.get_gear_stats({uuid}) / {name}", api.get_gear_stats(uuid)) - - elif i == "Z": - # Logout Garmin Connect portal - display_json("api.logout()", api.logout()) - api = None - - except ( - GarminConnectConnectionError, - GarminConnectAuthenticationError, - GarminConnectTooManyRequestsError, - requests.exceptions.HTTPError, - ) as err: - logger.error("Error occurred: %s", err) - except KeyError: - # Invalid menu option chosen - pass - else: - print("Could not login to Garmin Connect, try again later.") - -# Main program loop -while True: - # Display header and login - print("\n*** Garmin Connect API Demo by cyberjunky ***\n") - - # Init API - if not api: - api = init_api(email, password) - - # Display menu - print_menu() - option = readchar.readkey() - switch(api, option) - -``` +The tests provide examples of how to use the library. ## Donations [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/cyberjunkynl/) diff --git a/garminconnect/__init__.py b/garminconnect/__init__.py index 4907d0b..3450b0d 100644 --- a/garminconnect/__init__.py +++ b/garminconnect/__init__.py @@ -1,426 +1,170 @@ -# -*- coding: utf-8 -*- - """Python 3 API wrapper for Garmin Connect to get your statistics.""" -import json import logging -import re -import requests -from enum import Enum, auto -from typing import Any, Dict, List import os +from enum import Enum, auto +from typing import Any, Dict, List, Optional -import cloudscraper - +import garth logger = logging.getLogger(__name__) -class ApiClient: - """Class for a single API endpoint.""" - - default_headers = { - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:66.0) Gecko/20100101 Firefox/66.0" - } - - def __init__(self, session, baseurl, headers=None, additional_headers=None): - """Return a new Client instance.""" - self.session = session - self.baseurl = baseurl - - if headers: - self.headers = headers - else: - self.headers = self.default_headers.copy() - - if additional_headers: - self.headers.update(additional_headers) - - def set_cookies(self, cookies): - logger.debug("Restoring cookies for saved session") - self.session.cookies.update(cookies) - - def get_cookies(self): - return self.session.cookies - - def clear_cookies(self): - self.session.cookies.clear() - - def url(self, addurl=None): - """Return the url for the API endpoint.""" - - path = f"https://{self.baseurl}" - if addurl is not None: - path += f"/{addurl}" - - return path - - def get(self, addurl, additional_headers=None, params=None): - """Make an API call using the GET method.""" - total_headers = self.headers.copy() - if additional_headers: - total_headers.update(additional_headers) - url = self.url(addurl) - - logger.debug("URL: %s", url) - logger.debug("Headers: %s", total_headers) - - try: - response = self.session.get(url, headers=total_headers, params=params) - response.raise_for_status() - return response - - except requests.exceptions.HTTPError as err: - if response.status_code == 429: - raise GarminConnectTooManyRequestsError("429 Too many requests: {url}") from err - if response.status_code == 401: - raise GarminConnectAuthenticationError("401 Authentication error: {url}") from err - if response.status_code == 403: - raise GarminConnectConnectionError(f"403 Forbidden error: {url}") from err - except requests.exceptions.ConnectionError as err: - raise GarminConnectConnectionError(f"Connection error: {url}") from err - except requests.exceptions.Timeout as err: - raise GarminConnectConnectionError(f"Timeout error: {url}") from err - except requests.exceptions.RequestException as err: - raise GarminConnectConnectionError(f"Request exception error: {url}") from err - - - def post(self, addurl, additional_headers=None, params=None, data=None, files=None): - """Make an API call using the POST method.""" - total_headers = self.headers.copy() - if additional_headers: - total_headers.update(additional_headers) - url = self.url(addurl) - - logger.debug("URL: %s", url) - logger.debug("Headers: %s", total_headers) - logger.debug("Data: %s", data) - - try: - response = self.session.post( - url, headers=total_headers, params=params, data=data, files=files - ) - response.raise_for_status() - return response - - except requests.exceptions.HTTPError as err: - if response.status_code == 429: - raise GarminConnectTooManyRequestsError("429 Too many requests: {url}") from err - if response.status_code == 401: - raise GarminConnectAuthenticationError("401 Authentication error: {url}") from err - if response.status_code == 403: - raise GarminConnectConnectionError(f"403 Forbidden error: {url}") from err - except requests.exceptions.ConnectionError as err: - raise GarminConnectConnectionError(f"Connection error: {url}") from err - except requests.exceptions.Timeout as err: - raise GarminConnectConnectionError(f"Timeout error: {url}") from err - except requests.exceptions.RequestException as err: - raise GarminConnectConnectionError(f"Request exception error: {url}") from err - - class Garmin: """Class for fetching data from Garmin Connect.""" - def __init__(self, email=None, password=None, is_cn=False, session_data=None): + def __init__(self, email=None, password=None, is_cn=False): """Create a new class instance.""" - self.session_data = session_data - self.username = email self.password = password self.is_cn = is_cn - self.garmin_connect_base_url = "https://connect.garmin.com" - self.garmin_connect_sso_url = "sso.garmin.com/sso" - self.garmin_connect_modern_url = "connect.garmin.com/modern" - self.garmin_connect_css_url = "https://static.garmincdn.com/com.garmin.connect/ui/css/gauth-custom-v1.2-min.css" - self.garmin_connect_login_url = self.garmin_connect_base_url + "/en-US/signin" - - if self.is_cn: - self.garmin_connect_base_url = "https://connect.garmin.cn" - self.garmin_connect_sso_url = "sso.garmin.cn/sso" - self.garmin_connect_modern_url = "connect.garmin.cn/modern" - self.garmin_connect_css_url = "https://static.garmincdn.cn/cn.garmin.connect/ui/css/gauth-custom-v1.2-min.css" - self.garmin_connect_login_url = self.garmin_connect_base_url + "/zh-CN/signin" - - self.garmin_connect_sso_login = "signin" - self.garmin_connect_devices_url = ( - "proxy/device-service/deviceregistration/devices" + "/device-service/deviceregistration/devices" + ) + self.garmin_connect_device_url = "/device-service/deviceservice" + self.garmin_connect_weight_url = ( + "/weight-service/weight/dateRange" ) - self.garmin_connect_device_url = "proxy/device-service/deviceservice" - self.garmin_connect_weight_url = "proxy/weight-service/weight/dateRange" self.garmin_connect_daily_summary_url = ( - "proxy/usersummary-service/usersummary/daily" + "/usersummary-service/usersummary/daily" + ) + self.garmin_connect_metrics_url = ( + "/metrics-service/metrics/maxmet/daily" ) - self.garmin_connect_metrics_url = "proxy/metrics-service/metrics/maxmet/daily" self.garmin_connect_daily_hydration_url = ( - "proxy/usersummary-service/usersummary/hydration/daily" + "/usersummary-service/usersummary/hydration/daily" ) self.garmin_connect_daily_stats_steps_url = ( - "proxy/usersummary-service/stats/steps/daily" + "/usersummary-service/stats/steps/daily" ) self.garmin_connect_personal_record_url = ( - "proxy/personalrecord-service/personalrecord/prs" + "/personalrecord-service/personalrecord/prs" + ) + self.garmin_connect_earned_badges_url = ( + "/badge-service/badge/earned" ) - self.garmin_connect_earned_badges_url = "proxy/badge-service/badge/earned" self.garmin_connect_adhoc_challenges_url = ( - "proxy/adhocchallenge-service/adHocChallenge/historical" + "/adhocchallenge-service/adHocChallenge/historical" ) self.garmin_connect_badge_challenges_url = ( - "proxy/badgechallenge-service/badgeChallenge/completed" + "/badgechallenge-service/badgeChallenge/completed" ) self.garmin_connect_available_badge_challenges_url = ( - "proxy/badgechallenge-service/badgeChallenge/available" + "/badgechallenge-service/badgeChallenge/available" ) self.garmin_connect_non_completed_badge_challenges_url = ( - "proxy/badgechallenge-service/badgeChallenge/non-completed" + "/badgechallenge-service/badgeChallenge/non-completed" ) self.garmin_connect_daily_sleep_url = ( - "proxy/wellness-service/wellness/dailySleepData" + "/wellness-service/wellness/dailySleepData" ) self.garmin_connect_daily_stress_url = ( - "proxy/wellness-service/wellness/dailyStress" + "/wellness-service/wellness/dailyStress" ) self.garmin_connect_daily_body_battery_url = ( - "proxy/wellness-service/wellness/bodyBattery/reports/daily" + "/wellness-service/wellness/bodyBattery/reports/daily" ) self.garmin_connect_blood_pressure_endpoint = ( - "proxy/bloodpressure-service/bloodpressure/range" + "/bloodpressure-service/bloodpressure/range" ) - self.garmin_connect_goals_url = "proxy/goal-service/goal/goals" + self.garmin_connect_goals_url = "/goal-service/goal/goals" - self.garmin_connect_rhr_url = "proxy/userstats-service/wellness/daily" + self.garmin_connect_rhr_url = "/userstats-service/wellness/daily" - self.garmin_connect_hrv_url = "proxy/hrv-service/hrv" + self.garmin_connect_hrv_url = "/hrv-service/hrv" - self.garmin_connect_training_readiness_url = "proxy/metrics-service/metrics/trainingreadiness" + self.garmin_connect_training_readiness_url = ( + "/metrics-service/metrics/trainingreadiness" + ) - self.garmin_connect_training_status_url = "proxy/metrics-service/metrics/trainingstatus/aggregated" + self.garmin_connect_training_status_url = ( + "/metrics-service/metrics/trainingstatus/aggregated" + ) self.garmin_connect_user_summary_chart = ( - "proxy/wellness-service/wellness/dailySummaryChart" + "/wellness-service/wellness/dailySummaryChart" ) self.garmin_connect_floors_chart_daily_url = ( - "proxy/wellness-service/wellness/floorsChartData/daily" + "/wellness-service/wellness/floorsChartData/daily" ) self.garmin_connect_heartrates_daily_url = ( - "proxy/wellness-service/wellness/dailyHeartRate" + "/wellness-service/wellness/dailyHeartRate" ) self.garmin_connect_daily_respiration_url = ( - "proxy/wellness-service/wellness/daily/respiration" + "/wellness-service/wellness/daily/respiration" ) self.garmin_connect_daily_spo2_url = ( - "proxy/wellness-service/wellness/daily/spo2" + "/wellness-service/wellness/daily/spo2" ) self.garmin_connect_activities = ( - "proxy/activitylist-service/activities/search/activities" + "/activitylist-service/activities/search/activities" + ) + self.garmin_connect_activity = "/activity-service/activity" + self.garmin_connect_activity_types = ( + "/activity-service/activity/activityTypes" ) - self.garmin_connect_activity = "proxy/activity-service/activity" - self.garmin_connect_activity_types = "proxy/activity-service/activity/activityTypes" - self.garmin_connect_fitnessstats = "proxy/fitnessstats-service/activity" + self.garmin_connect_fitnessstats = ( + "/fitnessstats-service/activity" + ) - self.garmin_connect_fit_download = "proxy/download-service/files/activity" - self.garmin_connect_tcx_download = "proxy/download-service/export/tcx/activity" - self.garmin_connect_gpx_download = "proxy/download-service/export/gpx/activity" - self.garmin_connect_kml_download = "proxy/download-service/export/kml/activity" - self.garmin_connect_csv_download = "proxy/download-service/export/csv/activity" + self.garmin_connect_fit_download = ( + "/download-service/files/activity" + ) + self.garmin_connect_tcx_download = ( + "/download-service/export/tcx/activity" + ) + self.garmin_connect_gpx_download = ( + "/download-service/export/gpx/activity" + ) + self.garmin_connect_kml_download = ( + "/download-service/export/kml/activity" + ) + self.garmin_connect_csv_download = ( + "/download-service/export/csv/activity" + ) - self.garmin_connect_upload = "proxy/upload-service/upload" + self.garmin_connect_upload = "/upload-service/upload" - self.garmin_connect_gear = "proxy/gear-service/gear/filterGear" - self.garmin_connect_gear_baseurl = "proxy/gear-service/gear/" + self.garmin_connect_gear = "/gear-service/gear/filterGear" + self.garmin_connect_gear_baseurl = "/gear-service/gear/" self.garmin_connect_logout = "auth/logout/?url=" - self.garmin_headers = {"NK": "NT"} - - self.session = cloudscraper.CloudScraper() - self.sso_rest_client = ApiClient( - self.session, - self.garmin_connect_sso_url, - additional_headers=self.garmin_headers, - ) - self.modern_rest_client = ApiClient( - self.session, - self.garmin_connect_modern_url, - additional_headers=self.garmin_headers, + self.garth = garth.Client( + domain="garmin.cn" if is_cn else "garmin.com" ) self.display_name = None self.full_name = None self.unit_system = None - @staticmethod - def __get_json(page_html, key): - """Return json from text.""" - - found = re.search(key + r" = (\{.*\});", page_html, re.M) - if found: - json_text = found.group(1).replace('\\"', '"') - return json.loads(json_text) - - return None - - def login(self): - if self.session_data is None: - return self.authenticate() - else: - return self.login_session() - - def login_session(self): - logger.debug("Login with cookies") - - session_display_name = self.session_data["display_name"] - logger.debug("Set cookies in session") - self.modern_rest_client.set_cookies( - requests.utils.cookiejar_from_dict(self.session_data["session_cookies"]) - ) - self.sso_rest_client.set_cookies( - requests.utils.cookiejar_from_dict(self.session_data["login_cookies"]) - ) - - logger.debug("Get page data with cookies") - params = { - "service": "https://connect.garmin.com/modern/", - "webhost": "https://connect.garmin.com", - "gateway": "true", - "generateExtraServiceTicket": "true", - "generateTwoExtraServiceTickets": "true", - } - response = self.sso_rest_client.get("login", params=params) - logger.debug("Session response %s", response.status_code) - if response.status_code != 200: - logger.debug("Session expired, authenticating again!") - return self.authenticate() - - user_prefs = self.__get_json(response.text, "VIEWER_USERPREFERENCES") - if user_prefs is None: - logger.debug("Session expired, authenticating again!") - return self.authenticate() - - self.display_name = user_prefs["displayName"] - logger.debug("Display name is %s", self.display_name) + def connectapi(self, path, **kwargs): + return self.garth.connectapi(path, **kwargs) + + def download(self, path, **kwargs): + return self.garth.download(path, **kwargs) - self.unit_system = user_prefs["measurementSystem"] - logger.debug("Unit system is %s", self.unit_system) + def login(self, /, garth_home: Optional[str] = None): + """Log in using Garth""" + garth_home = garth_home or os.getenv("GARTH_HOME") - social_profile = self.__get_json(response.text, "VIEWER_SOCIAL_PROFILE") - self.full_name = social_profile["fullName"] - logger.debug("Fullname is %s", self.full_name) - - if self.display_name == session_display_name: - return True + if garth_home: + self.garth.load(garth_home) else: - logger.debug("Session not valid for user %s", self.display_name) - return self.authenticate() - - def authenticate(self): - """Login to Garmin Connect.""" - - logger.debug("login: %s %s", self.username, self.password) - self.modern_rest_client.clear_cookies() - self.sso_rest_client.clear_cookies() - - get_headers = {"Referer": self.garmin_connect_login_url} - params = { - "service": self.modern_rest_client.url(), - "webhost": self.garmin_connect_base_url, - "source": self.garmin_connect_login_url, - "redirectAfterAccountLoginUrl": self.modern_rest_client.url(), - "redirectAfterAccountCreationUrl": self.modern_rest_client.url(), - "gauthHost": self.sso_rest_client.url(), - "locale": "en_US", - "id": "gauth-widget", - "cssUrl": self.garmin_connect_css_url, - "privacyStatementUrl": "//connect.garmin.com/en-US/privacy/", - "clientId": "GarminConnect", - "rememberMeShown": "true", - "rememberMeChecked": "false", - "createAccountShown": "true", - "openCreateAccount": "false", - "displayNameShown": "false", - "consumeServiceTicket": "false", - "initialFocus": "true", - "embedWidget": "false", - "generateExtraServiceTicket": "true", - "generateTwoExtraServiceTickets": "false", - "generateNoServiceTicket": "false", - "globalOptInShown": "true", - "globalOptInChecked": "false", - "mobile": "false", - "connectLegalTerms": "true", - "locationPromptShown": "true", - "showPassword": "true", - } + self.garth.login(self.username, self.password) - if self.is_cn: - params[ - "cssUrl" - ] = "https://static.garmincdn.cn/cn.garmin.connect/ui/css/gauth-custom-v1.2-min.css" + self.display_name = self.garth.profile["displayName"] + self.full_name = self.garth.profile["fullName"] - response = self.sso_rest_client.get( - self.garmin_connect_sso_login, get_headers, params + settings = self.garth.connectapi( + "/userprofile-service/userprofile/user-settings" ) - - found = re.search(r"name=\"_csrf\" value=\"(\w*)", response.text, re.M) - if not found: - logger.error("_csrf not found (%d)", response.status_code) - return False - - csrf = found.group(1) - referer = response.url - logger.debug("_csrf found: %s", csrf) - logger.debug("Referer: %s", referer) - - data = { - "username": self.username, - "password": self.password, - "embed": "false", - "_csrf": csrf, - } - post_headers = { - "Referer": referer, - "Content-Type": "application/x-www-form-urlencoded", - } - - response = self.sso_rest_client.post( - self.garmin_connect_sso_login, post_headers, params, data - ) - - found = re.search(r"\?ticket=([\w-]*)", response.text, re.M) - if not found: - logger.error("Login ticket not found (%d).", response.status_code) - return False - params = {"ticket": found.group(1)} - - response = self.modern_rest_client.get("", params=params) - - user_prefs = self.__get_json(response.text, "VIEWER_USERPREFERENCES") - self.display_name = user_prefs["displayName"] - logger.debug("Display name is %s", self.display_name) - - self.unit_system = user_prefs["measurementSystem"] - logger.debug("Unit system is %s", self.unit_system) - - social_profile = self.__get_json(response.text, "VIEWER_SOCIAL_PROFILE") - self.full_name = social_profile["fullName"] - logger.debug("Fullname is %s", self.full_name) - - self.session_data = { - "display_name": self.display_name, - "session_cookies": requests.utils.dict_from_cookiejar( - self.modern_rest_client.get_cookies() - ), - "login_cookies": requests.utils.dict_from_cookiejar( - self.sso_rest_client.get_cookies() - ), - } - - logger.debug("Cookies saved") + self.unit_system = settings["userData"]["measurementSystem"] return True @@ -435,7 +179,10 @@ def get_unit_system(self): return self.unit_system def get_stats(self, cdate: str) -> Dict[str, Any]: - """Return user activity summary for 'cdate' format 'YYYY-MM-DD' (compat for garminconnect).""" + """ + Return user activity summary for 'cdate' format 'YYYY-MM-DD' + (compat for garminconnect). + """ return self.get_user_summary(cdate) @@ -443,12 +190,10 @@ def get_user_summary(self, cdate: str) -> Dict[str, Any]: """Return user activity summary for 'cdate' format 'YYYY-MM-DD'.""" url = f"{self.garmin_connect_daily_summary_url}/{self.display_name}" - params = { - "calendarDate": str(cdate) - } + params = {"calendarDate": str(cdate)} logger.debug("Requesting user summary") - response = self.modern_rest_client.get(url, params=params).json() + response = self.connectapi(url, params=params) if response["privacyProtected"] is True: raise GarminConnectAuthenticationError("Authentication error") @@ -459,39 +204,35 @@ def get_steps_data(self, cdate): """Fetch available steps data 'cDate' format 'YYYY-MM-DD'.""" url = f"{self.garmin_connect_user_summary_chart}/{self.display_name}" - params = { - "date": str(cdate) - } + params = {"date": str(cdate)} logger.debug("Requesting steps data") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_floors(self, cdate): """Fetch available floors data 'cDate' format 'YYYY-MM-DD'.""" - url = f'{self.garmin_connect_floors_chart_daily_url}/{cdate}' + url = f"{self.garmin_connect_floors_chart_daily_url}/{cdate}" logger.debug("Requesting floors data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_daily_steps(self, start, end): """Fetch available steps data 'start' and 'end' format 'YYYY-MM-DD'.""" - url = f'{self.garmin_connect_daily_stats_steps_url}/{start}/{end}' + url = f"{self.garmin_connect_daily_stats_steps_url}/{start}/{end}" logger.debug("Requesting daily steps data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_heart_rates(self, cdate): """Fetch available heart rates data 'cDate' format 'YYYY-MM-DD'.""" url = f"{self.garmin_connect_heartrates_daily_url}/{self.display_name}" - params = { - "date": str(cdate) - } + params = {"date": str(cdate)} logger.debug("Requesting heart rates") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_stats_and_body(self, cdate): """Return activity data and body composition (compat for garminconnect).""" @@ -501,8 +242,13 @@ def get_stats_and_body(self, cdate): **self.get_body_composition(cdate)["totalAverage"], } - def get_body_composition(self, startdate: str, enddate=None) -> Dict[str, Any]: - """Return available body composition data for 'startdate' format 'YYYY-MM-DD' through enddate 'YYYY-MM-DD'.""" + def get_body_composition( + self, startdate: str, enddate=None + ) -> Dict[str, Any]: + """ + Return available body composition data for 'startdate' format + 'YYYY-MM-DD' through enddate 'YYYY-MM-DD'. + """ if enddate is None: enddate = startdate @@ -510,10 +256,15 @@ def get_body_composition(self, startdate: str, enddate=None) -> Dict[str, Any]: params = {"startDate": str(startdate), "endDate": str(enddate)} logger.debug("Requesting body composition") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) - def get_body_battery(self, startdate: str, enddate=None) -> List[Dict[str, Any]]: - """Return body battery values by day for 'startdate' format 'YYYY-MM-DD' through enddate 'YYYY-MM-DD'""" + def get_body_battery( + self, startdate: str, enddate=None + ) -> List[Dict[str, Any]]: + """ + Return body battery values by day for 'startdate' format + 'YYYY-MM-DD' through enddate 'YYYY-MM-DD' + """ if enddate is None: enddate = startdate @@ -521,10 +272,15 @@ def get_body_battery(self, startdate: str, enddate=None) -> List[Dict[str, Any]] params = {"startDate": str(startdate), "endDate": str(enddate)} logger.debug("Requesting body battery data") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) - def get_blood_pressure(self, startdate: str, enddate=None) -> Dict[str, Any]: - """Returns blood pressure by day for 'startdate' format 'YYYY-MM-DD' through enddate 'YYYY-MM-DD'""" + def get_blood_pressure( + self, startdate: str, enddate=None + ) -> Dict[str, Any]: + """ + Returns blood pressure by day for 'startdate' format + 'YYYY-MM-DD' through enddate 'YYYY-MM-DD' + """ if enddate is None: enddate = startdate @@ -532,7 +288,7 @@ def get_blood_pressure(self, startdate: str, enddate=None) -> Dict[str, Any]: params = {"includeAll": True} logger.debug("Requesting blood pressure data") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_max_metrics(self, cdate: str) -> Dict[str, Any]: """Return available max metric data for 'cdate' format 'YYYY-MM-DD'.""" @@ -540,7 +296,7 @@ def get_max_metrics(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_metrics_url}/{cdate}/{cdate}" logger.debug("Requesting max metrics") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_hydration_data(self, cdate: str) -> Dict[str, Any]: """Return available hydration data 'cdate' format 'YYYY-MM-DD'.""" @@ -548,7 +304,7 @@ def get_hydration_data(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_daily_hydration_url}/{cdate}" logger.debug("Requesting hydration data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_respiration_data(self, cdate: str) -> Dict[str, Any]: """Return available respiration data 'cdate' format 'YYYY-MM-DD'.""" @@ -556,7 +312,7 @@ def get_respiration_data(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_daily_respiration_url}/{cdate}" logger.debug("Requesting respiration data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_spo2_data(self, cdate: str) -> Dict[str, Any]: """Return available SpO2 data 'cdate' format 'YYYY-MM-DD'.""" @@ -564,7 +320,7 @@ def get_spo2_data(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_daily_spo2_url}/{cdate}" logger.debug("Requesting SpO2 data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_personal_record(self) -> Dict[str, Any]: """Return personal records for current user.""" @@ -572,7 +328,7 @@ def get_personal_record(self) -> Dict[str, Any]: url = f"{self.garmin_connect_personal_record_url}/{self.display_name}" logger.debug("Requesting personal records for user") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_earned_badges(self) -> Dict[str, Any]: """Return earned badges for current user.""" @@ -580,7 +336,7 @@ def get_earned_badges(self) -> Dict[str, Any]: url = self.garmin_connect_earned_badges_url logger.debug("Requesting earned badges for user") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_adhoc_challenges(self, start, limit) -> Dict[str, Any]: """Return adhoc challenges for current user.""" @@ -589,7 +345,7 @@ def get_adhoc_challenges(self, start, limit) -> Dict[str, Any]: params = {"start": str(start), "limit": str(limit)} logger.debug("Requesting adhoc challenges for user") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_badge_challenges(self, start, limit) -> Dict[str, Any]: """Return badge challenges for current user.""" @@ -598,7 +354,7 @@ def get_badge_challenges(self, start, limit) -> Dict[str, Any]: params = {"start": str(start), "limit": str(limit)} logger.debug("Requesting badge challenges for user") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_available_badge_challenges(self, start, limit) -> Dict[str, Any]: """Return available badge challenges.""" @@ -607,16 +363,18 @@ def get_available_badge_challenges(self, start, limit) -> Dict[str, Any]: params = {"start": str(start), "limit": str(limit)} logger.debug("Requesting available badge challenges") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) - def get_non_completed_badge_challenges(self, start, limit) -> Dict[str, Any]: + def get_non_completed_badge_challenges( + self, start, limit + ) -> Dict[str, Any]: """Return badge non-completed challenges for current user.""" url = self.garmin_connect_non_completed_badge_challenges_url params = {"start": str(start), "limit": str(limit)} logger.debug("Requesting badge challenges for user") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_sleep_data(self, cdate: str) -> Dict[str, Any]: """Return sleep data for current user.""" @@ -625,7 +383,7 @@ def get_sleep_data(self, cdate: str) -> Dict[str, Any]: params = {"date": str(cdate), "nonSleepBufferMinutes": 60} logger.debug("Requesting sleep data") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_stress_data(self, cdate: str) -> Dict[str, Any]: """Return stress data for current user.""" @@ -633,16 +391,20 @@ def get_stress_data(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_daily_stress_url}/{cdate}" logger.debug("Requesting stress data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_rhr_day(self, cdate: str) -> Dict[str, Any]: """Return resting heartrate data for current user.""" url = f"{self.garmin_connect_rhr_url}/{self.display_name}" - params = {"fromDate": str(cdate), "untilDate": str(cdate), "metricId": 60} + params = { + "fromDate": str(cdate), + "untilDate": str(cdate), + "metricId": 60, + } logger.debug("Requesting resting heartrate data") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_hrv_data(self, cdate: str) -> Dict[str, Any]: """Return Heart Rate Variability (hrv) data for current user.""" @@ -650,7 +412,7 @@ def get_hrv_data(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_hrv_url}/{cdate}" logger.debug("Requesting Heart Rate Variability (hrv) data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_training_readiness(self, cdate: str) -> Dict[str, Any]: """Return training readiness data for current user.""" @@ -658,7 +420,7 @@ def get_training_readiness(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_training_readiness_url}/{cdate}" logger.debug("Requesting training readiness data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_training_status(self, cdate: str) -> Dict[str, Any]: """Return training status data for current user.""" @@ -666,7 +428,7 @@ def get_training_status(self, cdate: str) -> Dict[str, Any]: url = f"{self.garmin_connect_training_status_url}/{cdate}" logger.debug("Requesting training status data") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_devices(self) -> Dict[str, Any]: """Return available devices for the current user account.""" @@ -674,7 +436,7 @@ def get_devices(self) -> Dict[str, Any]: url = self.garmin_connect_devices_url logger.debug("Requesting devices") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_device_settings(self, device_id: str) -> Dict[str, Any]: """Return device settings for device with 'device_id'.""" @@ -682,7 +444,7 @@ def get_device_settings(self, device_id: str) -> Dict[str, Any]: url = f"{self.garmin_connect_device_url}/device-info/settings/{device_id}" logger.debug("Requesting device settings") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_device_alarms(self) -> Dict[str, Any]: """Get list of active alarms from all devices.""" @@ -704,7 +466,7 @@ def get_device_last_used(self): url = f"{self.garmin_connect_device_url}/mylastused" logger.debug("Requesting device last used") - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activities(self, start, limit): """Return available activities.""" @@ -713,7 +475,7 @@ def get_activities(self, start, limit): params = {"start": str(start), "limit": str(limit)} logger.debug("Requesting activities") - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_last_activity(self): """Return last activity.""" @@ -730,16 +492,20 @@ def upload_activity(self, activity_path: str): file_base_name = os.path.basename(activity_path) file_extension = file_base_name.split(".")[-1] - allowed_file_extension = file_extension.upper() in Garmin.ActivityUploadFormat.__members__ + allowed_file_extension = ( + file_extension.upper() in Garmin.ActivityUploadFormat.__members__ + ) if allowed_file_extension: files = { "file": (file_base_name, open(activity_path, "rb" or "r")), } url = self.garmin_connect_upload - return self.modern_rest_client.post(url, files=files).json() + return self.garth.post("connectapi", url, files=files) else: - raise GarminConnectInvalidFileFormatError(f"Could not upload {activity_path}") + raise GarminConnectInvalidFileFormatError( + f"Could not upload {activity_path}" + ) def get_activities_by_date(self, startdate, enddate, activitytype=None): """ @@ -755,7 +521,8 @@ def get_activities_by_date(self, startdate, enddate, activitytype=None): activities = [] start = 0 limit = 20 - # mimicking the behavior of the web interface that fetches 20 activities at a time + # mimicking the behavior of the web interface that fetches + # 20 activities at a time # and automatically loads more on scroll url = self.garmin_connect_activities params = { @@ -767,11 +534,13 @@ def get_activities_by_date(self, startdate, enddate, activitytype=None): if activitytype: params["activityType"] = str(activitytype) - logger.debug(f"Requesting activities by date from {startdate} to {enddate}") + logger.debug( + f"Requesting activities by date from {startdate} to {enddate}" + ) while True: params["start"] = str(start) logger.debug(f"Requesting activities {start} to {start+limit}") - act = self.modern_rest_client.get(url, params=params).json() + act = self.connectapi(url, params=params) if act: activities.extend(act) start = start + limit @@ -780,7 +549,9 @@ def get_activities_by_date(self, startdate, enddate, activitytype=None): return activities - def get_progress_summary_between_dates(self, startdate, enddate, metric="distance"): + def get_progress_summary_between_dates( + self, startdate, enddate, metric="distance" + ): """ Fetch progress summary data between specific dates :param startdate: String in the format YYYY-MM-DD @@ -796,18 +567,18 @@ def get_progress_summary_between_dates(self, startdate, enddate, metric="distanc "endDate": str(enddate), "aggregation": "lifetime", "groupByParentActivityType": "true", - "metric": str(metric) - + "metric": str(metric), } logger.debug( - f"Requesting fitnessstats by date from {startdate} to {enddate}") - return self.modern_rest_client.get(url, params=params).json() + f"Requesting fitnessstats by date from {startdate} to {enddate}" + ) + return self.connectapi(url, params=params) def get_activity_types(self): url = self.garmin_connect_activity_types - logger.debug(f"Requesting activy types") - return self.modern_rest_client.get(url).json() + logger.debug("Requesting activy types") + return self.connectapi(url) def get_goals(self, status="active", start=1, limit=30): """ @@ -827,14 +598,16 @@ def get_goals(self, status="active", start=1, limit=30): "status": status, "start": str(start), "limit": str(limit), - "sortOrder": "asc" + "sortOrder": "asc", } logger.debug(f"Requesting {status} goals") while True: params["start"] = str(start) - logger.debug(f"Requesting {status} goals {start} to {start + limit - 1}") - goals_json = self.modern_rest_client.get(url, params=params).json() + logger.debug( + f"Requesting {status} goals {start} to {start + limit - 1}" + ) + goals_json = self.connectapi(url, params=params) if goals_json: goals.extend(goals_json) start = start + limit @@ -848,24 +621,32 @@ def get_gear(self, userProfileNumber): url = f"{self.garmin_connect_gear}?userProfilePk={userProfileNumber}" logger.debug("Requesting gear for user %s", userProfileNumber) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_gear_stats(self, gearUUID): url = f"{self.garmin_connect_gear_baseurl}stats/{gearUUID}" logger.debug("Requesting gear stats for gearUUID %s", gearUUID) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_gear_defaults(self, userProfileNumber): - url = f"{self.garmin_connect_gear_baseurl}user/{userProfileNumber}/activityTypes" + url = ( + f"{self.garmin_connect_gear_baseurl}user/" + f"{userProfileNumber}/activityTypes" + ) logger.debug("Requesting gear for user %s", userProfileNumber) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def set_gear_default(self, activityType, gearUUID, defaultGear=True): defaultGearString = "/default/true" if defaultGear else "" method_override = "PUT" if defaultGear else "DELETE" - url = f"{self.garmin_connect_gear_baseurl}{gearUUID}/activityType/{activityType}{defaultGearString}" - return self.modern_rest_client.post( - url, {"x-http-method-override": method_override} + url = ( + f"{self.garmin_connect_gear_baseurl}{gearUUID}/" + f"activityType/{activityType}{defaultGearString}" + ) + return self.garth.post( + "connectapi", + url, + {"x-http-method-override": method_override} ) class ActivityDownloadFormat(Enum): @@ -882,7 +663,9 @@ class ActivityUploadFormat(Enum): GPX = auto() TCX = auto() - def download_activity(self, activity_id, dl_fmt=ActivityDownloadFormat.TCX): + def download_activity( + self, activity_id, dl_fmt=ActivityDownloadFormat.TCX + ): """ Downloads activity in requested format and returns the raw bytes. For "Original" will return the zip file content, up to user to extract it. @@ -902,7 +685,7 @@ def download_activity(self, activity_id, dl_fmt=ActivityDownloadFormat.TCX): logger.debug("Downloading activities from %s", url) - return self.modern_rest_client.get(url).content + return self.download(url) def get_activity_splits(self, activity_id): """Return activity splits.""" @@ -911,16 +694,18 @@ def get_activity_splits(self, activity_id): url = f"{self.garmin_connect_activity}/{activity_id}/splits" logger.debug("Requesting splits for activity id %s", activity_id) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activity_split_summaries(self, activity_id): """Return activity split summaries.""" activity_id = str(activity_id) url = f"{self.garmin_connect_activity}/{activity_id}/split_summaries" - logger.debug("Requesting split summaries for activity id %s", activity_id) + logger.debug( + "Requesting split summaries for activity id %s", activity_id + ) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activity_weather(self, activity_id): """Return activity weather.""" @@ -929,25 +714,29 @@ def get_activity_weather(self, activity_id): url = f"{self.garmin_connect_activity}/{activity_id}/weather" logger.debug("Requesting weather for activity id %s", activity_id) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activity_hr_in_timezones(self, activity_id): """Return activity heartrate in timezones.""" activity_id = str(activity_id) url = f"{self.garmin_connect_activity}/{activity_id}/hrTimeInZones" - logger.debug("Requesting split summaries for activity id %s", activity_id) + logger.debug( + "Requesting split summaries for activity id %s", activity_id + ) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activity_evaluation(self, activity_id): """Return activity self evaluation details.""" activity_id = str(activity_id) url = f"{self.garmin_connect_activity}/{activity_id}" - logger.debug("Requesting self evaluation data for activity id %s", activity_id) + logger.debug( + "Requesting self evaluation data for activity id %s", activity_id + ) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activity_details(self, activity_id, maxchart=2000, maxpoly=4000): """Return activity details.""" @@ -960,16 +749,18 @@ def get_activity_details(self, activity_id, maxchart=2000, maxpoly=4000): url = f"{self.garmin_connect_activity}/{activity_id}/details" logger.debug("Requesting details for activity id %s", activity_id) - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def get_activity_exercise_sets(self, activity_id): - """Return activity exercise sets.""" + """Return activity exercise sets.""" - activity_id = str(activity_id) - url = f"{self.garmin_connect_activity}/{activity_id}/exerciseSets" - logger.debug("Requesting exercise sets for activity id %s", activity_id) + activity_id = str(activity_id) + url = f"{self.garmin_connect_activity}/{activity_id}/exerciseSets" + logger.debug( + "Requesting exercise sets for activity id %s", activity_id + ) - return self.modern_rest_client.get(url).json() + return self.connectapi(url) def get_activity_gear(self, activity_id): """Return gears used for activity id.""" @@ -981,12 +772,12 @@ def get_activity_gear(self, activity_id): url = self.garmin_connect_gear logger.debug("Requesting gear for activity_id %s", activity_id) - return self.modern_rest_client.get(url, params=params).json() + return self.connectapi(url, params=params) def logout(self): """Log user out of session.""" - self.modern_rest_client.get(self.garmin_connect_logout) + self.connectapi(self.garmin_connect_logout) class GarminConnectConnectionError(Exception): diff --git a/reference.ipynb b/reference.ipynb new file mode 100644 index 0000000..593dbe6 --- /dev/null +++ b/reference.ipynb @@ -0,0 +1,500 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Garth Migration" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import garminconnect" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Login" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Request email and password. If MFA is enabled, Garth will request it." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'mtamizi'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from getpass import getpass\n", + "\n", + "email = input(\"Enter email address: \")\n", + "password = getpass(\"Enter password: \")\n", + "\n", + "garmin = garminconnect.Garmin(email, password)\n", + "garmin.login()\n", + "\n", + "garmin.display_name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save session" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "GARTH_HOME = os.getenv(\"GARTH_HOME\", \"~/.garth\")\n", + "garmin.garth.dump(GARTH_HOME)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Connect stats" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'2023-08-05'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from datetime import date, timedelta\n", + "\n", + "yesterday = date.today() - timedelta(days=1)\n", + "yesterday = yesterday.isoformat()\n", + "yesterday" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['userProfileId', 'totalKilocalories', 'activeKilocalories', 'bmrKilocalories', 'wellnessKilocalories', 'burnedKilocalories', 'consumedKilocalories', 'remainingKilocalories', 'totalSteps', 'netCalorieGoal', 'totalDistanceMeters', 'wellnessDistanceMeters', 'wellnessActiveKilocalories', 'netRemainingKilocalories', 'userDailySummaryId', 'calendarDate', 'rule', 'uuid', 'dailyStepGoal', 'totalPushDistance', 'totalPushes', 'wellnessStartTimeGmt', 'wellnessStartTimeLocal', 'wellnessEndTimeGmt', 'wellnessEndTimeLocal', 'durationInMilliseconds', 'wellnessDescription', 'highlyActiveSeconds', 'activeSeconds', 'sedentarySeconds', 'sleepingSeconds', 'includesWellnessData', 'includesActivityData', 'includesCalorieConsumedData', 'privacyProtected', 'moderateIntensityMinutes', 'vigorousIntensityMinutes', 'floorsAscendedInMeters', 'floorsDescendedInMeters', 'floorsAscended', 'floorsDescended', 'intensityMinutesGoal', 'userFloorsAscendedGoal', 'minHeartRate', 'maxHeartRate', 'restingHeartRate', 'lastSevenDaysAvgRestingHeartRate', 'source', 'averageStressLevel', 'maxStressLevel', 'stressDuration', 'restStressDuration', 'activityStressDuration', 'uncategorizedStressDuration', 'totalStressDuration', 'lowStressDuration', 'mediumStressDuration', 'highStressDuration', 'stressPercentage', 'restStressPercentage', 'activityStressPercentage', 'uncategorizedStressPercentage', 'lowStressPercentage', 'mediumStressPercentage', 'highStressPercentage', 'stressQualifier', 'measurableAwakeDuration', 'measurableAsleepDuration', 'lastSyncTimestampGMT', 'minAvgHeartRate', 'maxAvgHeartRate', 'bodyBatteryChargedValue', 'bodyBatteryDrainedValue', 'bodyBatteryHighestValue', 'bodyBatteryLowestValue', 'bodyBatteryMostRecentValue', 'bodyBatteryVersion', 'abnormalHeartRateAlertsCount', 'averageSpo2', 'lowestSpo2', 'latestSpo2', 'latestSpo2ReadingTimeGmt', 'latestSpo2ReadingTimeLocal', 'averageMonitoringEnvironmentAltitude', 'restingCaloriesFromActivity', 'avgWakingRespirationValue', 'highestRespirationValue', 'lowestRespirationValue', 'latestRespirationValue', 'latestRespirationTimeGMT'])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_stats(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['userProfileId', 'totalKilocalories', 'activeKilocalories', 'bmrKilocalories', 'wellnessKilocalories', 'burnedKilocalories', 'consumedKilocalories', 'remainingKilocalories', 'totalSteps', 'netCalorieGoal', 'totalDistanceMeters', 'wellnessDistanceMeters', 'wellnessActiveKilocalories', 'netRemainingKilocalories', 'userDailySummaryId', 'calendarDate', 'rule', 'uuid', 'dailyStepGoal', 'totalPushDistance', 'totalPushes', 'wellnessStartTimeGmt', 'wellnessStartTimeLocal', 'wellnessEndTimeGmt', 'wellnessEndTimeLocal', 'durationInMilliseconds', 'wellnessDescription', 'highlyActiveSeconds', 'activeSeconds', 'sedentarySeconds', 'sleepingSeconds', 'includesWellnessData', 'includesActivityData', 'includesCalorieConsumedData', 'privacyProtected', 'moderateIntensityMinutes', 'vigorousIntensityMinutes', 'floorsAscendedInMeters', 'floorsDescendedInMeters', 'floorsAscended', 'floorsDescended', 'intensityMinutesGoal', 'userFloorsAscendedGoal', 'minHeartRate', 'maxHeartRate', 'restingHeartRate', 'lastSevenDaysAvgRestingHeartRate', 'source', 'averageStressLevel', 'maxStressLevel', 'stressDuration', 'restStressDuration', 'activityStressDuration', 'uncategorizedStressDuration', 'totalStressDuration', 'lowStressDuration', 'mediumStressDuration', 'highStressDuration', 'stressPercentage', 'restStressPercentage', 'activityStressPercentage', 'uncategorizedStressPercentage', 'lowStressPercentage', 'mediumStressPercentage', 'highStressPercentage', 'stressQualifier', 'measurableAwakeDuration', 'measurableAsleepDuration', 'lastSyncTimestampGMT', 'minAvgHeartRate', 'maxAvgHeartRate', 'bodyBatteryChargedValue', 'bodyBatteryDrainedValue', 'bodyBatteryHighestValue', 'bodyBatteryLowestValue', 'bodyBatteryMostRecentValue', 'bodyBatteryVersion', 'abnormalHeartRateAlertsCount', 'averageSpo2', 'lowestSpo2', 'latestSpo2', 'latestSpo2ReadingTimeGmt', 'latestSpo2ReadingTimeLocal', 'averageMonitoringEnvironmentAltitude', 'restingCaloriesFromActivity', 'avgWakingRespirationValue', 'highestRespirationValue', 'lowestRespirationValue', 'latestRespirationValue', 'latestRespirationTimeGMT'])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_user_summary(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'startGMT': '2023-08-05T06:00:00.0',\n", + " 'endGMT': '2023-08-05T06:15:00.0',\n", + " 'steps': 0,\n", + " 'pushes': 0,\n", + " 'primaryActivityLevel': 'sedentary',\n", + " 'activityLevelConstant': True},\n", + " {'startGMT': '2023-08-05T06:15:00.0',\n", + " 'endGMT': '2023-08-05T06:30:00.0',\n", + " 'steps': 0,\n", + " 'pushes': 0,\n", + " 'primaryActivityLevel': 'sleeping',\n", + " 'activityLevelConstant': False}]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_steps_data(yesterday)[:2]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['startTimestampGMT', 'endTimestampGMT', 'startTimestampLocal', 'endTimestampLocal', 'floorsValueDescriptorDTOList', 'floorValuesArray'])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_floors(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'calendarDate': '2023-08-05',\n", + " 'totalSteps': 17945,\n", + " 'totalDistance': 14352,\n", + " 'stepGoal': 8560}]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_daily_steps(yesterday, yesterday)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['userProfilePK', 'calendarDate', 'startTimestampGMT', 'endTimestampGMT', 'startTimestampLocal', 'endTimestampLocal', 'maxHeartRate', 'minHeartRate', 'restingHeartRate', 'lastSevenDaysAvgRestingHeartRate', 'heartRateValueDescriptors', 'heartRateValues'])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_heart_rates(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['userProfileId', 'totalKilocalories', 'activeKilocalories', 'bmrKilocalories', 'wellnessKilocalories', 'burnedKilocalories', 'consumedKilocalories', 'remainingKilocalories', 'totalSteps', 'netCalorieGoal', 'totalDistanceMeters', 'wellnessDistanceMeters', 'wellnessActiveKilocalories', 'netRemainingKilocalories', 'userDailySummaryId', 'calendarDate', 'rule', 'uuid', 'dailyStepGoal', 'totalPushDistance', 'totalPushes', 'wellnessStartTimeGmt', 'wellnessStartTimeLocal', 'wellnessEndTimeGmt', 'wellnessEndTimeLocal', 'durationInMilliseconds', 'wellnessDescription', 'highlyActiveSeconds', 'activeSeconds', 'sedentarySeconds', 'sleepingSeconds', 'includesWellnessData', 'includesActivityData', 'includesCalorieConsumedData', 'privacyProtected', 'moderateIntensityMinutes', 'vigorousIntensityMinutes', 'floorsAscendedInMeters', 'floorsDescendedInMeters', 'floorsAscended', 'floorsDescended', 'intensityMinutesGoal', 'userFloorsAscendedGoal', 'minHeartRate', 'maxHeartRate', 'restingHeartRate', 'lastSevenDaysAvgRestingHeartRate', 'source', 'averageStressLevel', 'maxStressLevel', 'stressDuration', 'restStressDuration', 'activityStressDuration', 'uncategorizedStressDuration', 'totalStressDuration', 'lowStressDuration', 'mediumStressDuration', 'highStressDuration', 'stressPercentage', 'restStressPercentage', 'activityStressPercentage', 'uncategorizedStressPercentage', 'lowStressPercentage', 'mediumStressPercentage', 'highStressPercentage', 'stressQualifier', 'measurableAwakeDuration', 'measurableAsleepDuration', 'lastSyncTimestampGMT', 'minAvgHeartRate', 'maxAvgHeartRate', 'bodyBatteryChargedValue', 'bodyBatteryDrainedValue', 'bodyBatteryHighestValue', 'bodyBatteryLowestValue', 'bodyBatteryMostRecentValue', 'bodyBatteryVersion', 'abnormalHeartRateAlertsCount', 'averageSpo2', 'lowestSpo2', 'latestSpo2', 'latestSpo2ReadingTimeGmt', 'latestSpo2ReadingTimeLocal', 'averageMonitoringEnvironmentAltitude', 'restingCaloriesFromActivity', 'avgWakingRespirationValue', 'highestRespirationValue', 'lowestRespirationValue', 'latestRespirationValue', 'latestRespirationTimeGMT', 'from', 'until', 'weight', 'bmi', 'bodyFat', 'bodyWater', 'boneMass', 'muscleMass', 'physiqueRating', 'visceralFat', 'metabolicAge'])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_stats_and_body(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'startDate': '2023-08-05',\n", + " 'endDate': '2023-08-05',\n", + " 'dateWeightList': [],\n", + " 'totalAverage': {'from': 1691193600000,\n", + " 'until': 1691279999999,\n", + " 'weight': None,\n", + " 'bmi': None,\n", + " 'bodyFat': None,\n", + " 'bodyWater': None,\n", + " 'boneMass': None,\n", + " 'muscleMass': None,\n", + " 'physiqueRating': None,\n", + " 'visceralFat': None,\n", + " 'metabolicAge': None}}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_body_composition(yesterday)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['date', 'charged', 'drained', 'startTimestampGMT', 'endTimestampGMT', 'startTimestampLocal', 'endTimestampLocal', 'bodyBatteryValuesArray', 'bodyBatteryValueDescriptorDTOList'])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_body_battery(yesterday)[0].keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'from': '2023-08-05',\n", + " 'until': '2023-08-05',\n", + " 'measurementSummaries': [],\n", + " 'categoryStats': None}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_blood_pressure(yesterday)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_max_metrics(yesterday)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'userId': 2591602,\n", + " 'calendarDate': '2023-08-05',\n", + " 'valueInML': 0.0,\n", + " 'goalInML': 3437.0,\n", + " 'dailyAverageinML': None,\n", + " 'lastEntryTimestampLocal': '2023-08-05T12:25:27.0',\n", + " 'sweatLossInML': 637.0,\n", + " 'activityIntakeInML': 0.0}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_hydration_data(yesterday)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['userProfilePK', 'calendarDate', 'startTimestampGMT', 'endTimestampGMT', 'startTimestampLocal', 'endTimestampLocal', 'sleepStartTimestampGMT', 'sleepEndTimestampGMT', 'sleepStartTimestampLocal', 'sleepEndTimestampLocal', 'tomorrowSleepStartTimestampGMT', 'tomorrowSleepEndTimestampGMT', 'tomorrowSleepStartTimestampLocal', 'tomorrowSleepEndTimestampLocal', 'lowestRespirationValue', 'highestRespirationValue', 'avgWakingRespirationValue', 'avgSleepRespirationValue', 'avgTomorrowSleepRespirationValue', 'respirationValueDescriptorsDTOList', 'respirationValuesArray'])" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_respiration_data(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['userProfilePK', 'calendarDate', 'startTimestampGMT', 'endTimestampGMT', 'startTimestampLocal', 'endTimestampLocal', 'sleepStartTimestampGMT', 'sleepEndTimestampGMT', 'sleepStartTimestampLocal', 'sleepEndTimestampLocal', 'tomorrowSleepStartTimestampGMT', 'tomorrowSleepEndTimestampGMT', 'tomorrowSleepStartTimestampLocal', 'tomorrowSleepEndTimestampLocal', 'averageSpO2', 'lowestSpO2', 'lastSevenDaysAvgSpO2', 'latestSpO2', 'latestSpO2TimestampGMT', 'latestSpO2TimestampLocal', 'avgSleepSpO2', 'avgTomorrowSleepSpO2', 'spO2ValueDescriptorsDTOList', 'spO2SingleValues', 'continuousReadingDTOList', 'spO2HourlyAverages'])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_spo2_data(yesterday).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': 1944943000,\n", + " 'typeId': 16,\n", + " 'activityId': 0,\n", + " 'activityName': None,\n", + " 'activityStartDateTimeInGMT': None,\n", + " 'actStartDateTimeInGMTFormatted': None,\n", + " 'activityStartDateTimeLocal': None,\n", + " 'activityStartDateTimeLocalFormatted': None,\n", + " 'value': 2.0,\n", + " 'prStartTimeGmt': 1691215200000,\n", + " 'prStartTimeGmtFormatted': '2023-08-05T06:00:00.0',\n", + " 'prStartTimeLocal': 1691193600000,\n", + " 'prStartTimeLocalFormatted': '2023-08-05T00:00:00.0',\n", + " 'prTypeLabelKey': None,\n", + " 'poolLengthUnit': None},\n", + " {'id': 2184086093,\n", + " 'typeId': 3,\n", + " 'activityId': 10161959373,\n", + " 'activityName': 'Cuauhtémoc - Threshold',\n", + " 'activityStartDateTimeInGMT': 1671549377000,\n", + " 'actStartDateTimeInGMTFormatted': '2022-12-20T15:16:17.0',\n", + " 'activityStartDateTimeLocal': 1671527777000,\n", + " 'activityStartDateTimeLocalFormatted': '2022-12-20T09:16:17.0',\n", + " 'value': 1413.6650390625,\n", + " 'prStartTimeGmt': 1671549990000,\n", + " 'prStartTimeGmtFormatted': '2022-12-20T15:26:30.0',\n", + " 'prStartTimeLocal': None,\n", + " 'prStartTimeLocalFormatted': None,\n", + " 'prTypeLabelKey': None,\n", + " 'poolLengthUnit': None}]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "garmin.get_personal_record()[:2]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000..214210c --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,3 @@ +pytest +pytest-vcr +pytest-cov diff --git a/setup.py b/setup.py index 9595af5..7f543b1 100644 --- a/setup.py +++ b/setup.py @@ -30,10 +30,10 @@ def read(*parts): name="garminconnect", keywords=["garmin connect", "api", "client"], license="MIT license", - install_requires=["requests","cloudscraper"], + install_requires=["garth >= 0.4.23"], long_description_content_type="text/markdown", long_description=readme, url="https://github.com/cyberjunky/python-garminconnect", packages=["garminconnect"], - version="0.1.55" + version="0.2.1" ) diff --git a/tests/cassettes/test_body_battery.yaml b/tests/cassettes/test_body_battery.yaml new file mode 100644 index 0000000..d4cf34d --- /dev/null +++ b/tests/cassettes/test_body_battery.yaml @@ -0,0 +1,150 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a7b014d17b6e2-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 13:25:02 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=5fw6qcq0NdNdbleOS%2BWsMpFjTu6%2BU2E7IbbvmX8RF38%2Fitx8T5Eai8xRMWKiC%2F728gP0zlJeNtiIprepe9WLjNWkKmBb4g%2F2KiF7%2FRzTL3epslvndR22jovxvhF7Y5HZXsL%2Fzw4pRA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/wellness-service/wellness/bodyBattery/reports/daily?startDate=2023-07-01&endDate=2023-07-01 + response: + body: + string: '[{"date": "2023-07-01", "charged": 43, "drained": 43, "startTimestampGMT": + "2023-07-01T06:00:00.0", "endTimestampGMT": "2023-07-02T06:00:00.0", "startTimestampLocal": + "2023-07-01T00:00:00.0", "endTimestampLocal": "2023-07-02T00:00:00.0", "bodyBatteryValuesArray": + [[1688191200000, 5], [1688214060000, 48], [1688220000000, 41], [1688248260000, + 23], [1688248800000, 23], [1688269140000, 5]], "bodyBatteryValueDescriptorDTOList": + [{"bodyBatteryValueDescriptorIndex": 0, "bodyBatteryValueDescriptorKey": "timestamp"}, + {"bodyBatteryValueDescriptorIndex": 1, "bodyBatteryValueDescriptorKey": "bodyBatteryLevel"}]}]' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a7b0288481549-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 13:25:02 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=vuNozV%2Btdqrb2pnWC8vZa8XsRe8ATc8162AEj6jyD7wtVGJRTuI3LHxioV%2BMV%2FGZ%2BwoicMvVtiKVYZl2xLmGkhhuglHn0eUgQ7TtGcBIOHDPqxdHxwMC%2BbkPjL6ZgxgExIOyFPSPqQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_body_composition.yaml b/tests/cassettes/test_body_composition.yaml new file mode 100644 index 0000000..c8e042e --- /dev/null +++ b/tests/cassettes/test_body_composition.yaml @@ -0,0 +1,243 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a76f769ba154b-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 13:22:16 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=lo9dkCkcmm6pDJ7C8KfF9H5Xsm6EbKYAx5OGFo2CxXMSvazLtN2abgat2ArkGI7%2FT4Dce9ol7dMfHKTsMIz%2F7EfBUyrEf%2BZp6uYs%2BErKS0GqJxQHwgfLk%2Fc9gVSiA6mpJxTDRgN7pg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a76f84f181549-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 13:22:17 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=SX4h8ANa8PBe0mV0%2FZc0DXrBiAG602wMOfwDx3byFBPbwvKmlIRkoZMn%2BU9DiJr25G9rAoczD4hxiZ6kJcJ0NOuTVr773ki%2FHVtFtDr7zVfqJsiPvlZZOva4bJGbIyMOD6ZlYNPVZA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/weight-service/weight/dateRange?startDate=2023-07-01&endDate=2023-07-01 + response: + body: + string: '{"startDate": "2023-07-01", "endDate": "2023-07-01", "dateWeightList": + [], "totalAverage": {"from": 1688169600000, "until": 1688255999999, "weight": + null, "bmi": null, "bodyFat": null, "bodyWater": null, "boneMass": null, "muscleMass": + null, "physiqueRating": null, "visceralFat": null, "metabolicAge": null}}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a76f95d5b154b-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 13:22:17 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=WlbmmdUw8POQfCo2mGGrioz8FYa2CwVacFV6T0SHkjcsivJxi%2FFXkVlGkxa0g7lgrgCiEAxuC%2BZZRmvbJmeEV9ifNtvGnh3av7y7Kf3LfMXN56dzSELEhAl7br0lBvAiC40I2fSgNA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_daily_steps.yaml b/tests/cassettes/test_daily_steps.yaml new file mode 100644 index 0000000..bb82653 --- /dev/null +++ b/tests/cassettes/test_daily_steps.yaml @@ -0,0 +1,149 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8742c799e3477e-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 04:02:22 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=czRLz0eUqHstTuo2H%2FYUb52Rz7eVD5R9UOXsKHcFLC0FAHNqwLMRCxUKnR%2Fynq5azwvix59xAqI1mcvAmo4nw4DfQCJjrNE6gzdz6Vxo6%2F2PuIQiirUxV21XXXnYdg%2BdZVi5zsW2JA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/usersummary-service/stats/steps/daily/2023-07-01/2023-07-01 + response: + body: + string: '[{"calendarDate": "2023-07-01", "totalSteps": 12413, "totalDistance": + 10368, "stepGoal": 7950}]' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8742c8d857154a-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 04:02:22 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=LOAJ0KmYwtWF%2FFcsOa642XdT7pWAnsZuRlnwrgarfZslIB7JmldRym430NLhzrJhu4gjXPM4lh97u0aVuZLVe7ZEc4Bh7eA3iK%2FiCAzsAejjZNEDSi2Tgd6jjesOcBL%2F6qCxo0%2FD1Q%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_download_activity.yaml b/tests/cassettes/test_download_activity.yaml new file mode 100644 index 0000000..5b2e92e --- /dev/null +++ b/tests/cassettes/test_download_activity.yaml @@ -0,0 +1,12962 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 82700.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 50.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 80520990a8541449-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Mon, 11 Sep 2023 18:40:07 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=mjfkUmmuM03wMYvK2AJhO5TiS8fgIQ0Rr4Tn0FDZbLmyrgDwnZzohCAQB9GHFLZHkKF4VJvtk9REsn%2FhvrbizjazrNPz4tQhAgReEaObZ5rSw3YG5skXuDnTKcD9VWBLfIO0dphghg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/download-service/export/tcx/activity/11998957007 + response: + body: + string: "\n\n \n + \ \n 2023-09-11T13:44:29.000Z\n + \ \n 4338.02\n + \ 0.0\n 151\n + \ \n 72\n \n + \ \n 96\n \n + \ Active\n Manual\n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 45\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 45\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 47\n \n + \ \n \n \n + \ \n \n \n + \ \n 46\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 48\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 90\n \n + \ \n \n \n + \ \n \n \n + \ \n 91\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 96\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 95\n \n + \ \n \n \n + \ \n \n \n + \ \n 94\n \n + \ \n \n \n + \ \n \n \n + \ \n 93\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 92\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 89\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 66\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 68\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 71\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 88\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 87\n \n + \ \n \n \n + \ \n \n \n + \ \n 86\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 85\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 84\n \n + \ \n \n \n + \ \n \n \n + \ \n 83\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 82\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 81\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 80\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 79\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 78\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 77\n \n + \ \n \n \n + \ \n \n \n + \ \n 76\n \n + \ \n \n \n + \ \n \n \n + \ \n 75\n \n + \ \n \n \n + \ \n \n \n + \ \n 74\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 73\n \n + \ \n \n \n + \ \n \n \n + \ \n 72\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 70\n \n + \ \n \n \n + \ \n \n \n + \ \n 69\n \n + \ \n \n \n + \ \n \n \n + \ \n 67\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 49\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 50\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 51\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 52\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 53\n \n + \ \n \n \n + \ \n \n \n + \ \n 54\n \n + \ \n \n \n + \ \n \n \n + \ \n 55\n \n + \ \n \n \n + \ \n \n \n + \ \n 56\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 57\n \n + \ \n \n \n + \ \n \n \n + \ \n 58\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 59\n \n + \ \n \n \n + \ \n \n \n + \ \n 60\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 65\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 64\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 61\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 62\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n + \ \n 63\n \n + \ \n \n \n + \ \n \n \n \n + \ \n \n \n + \ fenix 6X Sapphire\n 3329978681\n + \ 3291\n \n 26\n + \ 0\n 0\n + \ 0\n \n \n + \ \n \n \n + \ Connect Api\n \n \n 0\n + \ 0\n 0\n + \ 0\n \n \n en\n + \ 006-D2449-00\n \n\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 80520992b990ea98-DFW + Connection: + - keep-alive + Content-Type: + - application/vnd.garmin.tcx+xml + Date: + - Mon, 11 Sep 2023 18:40:08 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=rvnC%2FcYg065EoSEomRiV7Oq%2FuwPFFhuPAmrhDEX%2B6i%2Fo5pabl%2B0mYJ7DUHhSH8Dp1qhHdKSWlf9YwtGDPpy1YT55JAAEesRGDtPXsdNl8KKLX0dxHSvJXof%2BgbxxI1zq45dBk2kWXg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + content-disposition: + - attachment; filename=activity_11998957007.tcx + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTs=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_floors.yaml b/tests/cassettes/test_floors.yaml new file mode 100644 index 0000000..109e5cc --- /dev/null +++ b/tests/cassettes/test_floors.yaml @@ -0,0 +1,212 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8740a48af1155e-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 04:00:54 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=iYV7gIdYcQH86D%2B1SrhLDbvBU1beua9HcesS6kbu9jiIorHzXEtQVjoq49jR5udXvF3rCsKxWcURNblr%2FWyqhsirWC%2FiOfbWaxzB7ZAoozVD0QfB1DK5E1iU8bVsUO%2FQd%2F4sWjEDvQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/wellness-service/wellness/floorsChartData/daily/2023-07-01 + response: + body: + string: '{"startTimestampGMT": "2023-07-01T06:00:00.0", "endTimestampGMT": "2023-07-02T06:00:00.0", + "startTimestampLocal": "2023-07-01T00:00:00.0", "endTimestampLocal": "2023-07-02T00:00:00.0", + "floorsValueDescriptorDTOList": [{"key": "startTimeGMT", "index": 0}, {"key": + "endTimeGMT", "index": 1}, {"key": "floorsAscended", "index": 2}, {"key": + "floorsDescended", "index": 3}], "floorValuesArray": [["2023-07-01T06:00:00.0", + "2023-07-01T06:15:00.0", 0, 0], ["2023-07-01T06:15:00.0", "2023-07-01T06:30:00.0", + 0, 0], ["2023-07-01T06:30:00.0", "2023-07-01T06:45:00.0", 0, 0], ["2023-07-01T06:45:00.0", + "2023-07-01T07:00:00.0", 0, 0], ["2023-07-01T07:00:00.0", "2023-07-01T07:15:00.0", + 0, 0], ["2023-07-01T07:15:00.0", "2023-07-01T07:30:00.0", 0, 0], ["2023-07-01T07:30:00.0", + "2023-07-01T07:45:00.0", 0, 0], ["2023-07-01T07:45:00.0", "2023-07-01T08:00:00.0", + 0, 0], ["2023-07-01T08:00:00.0", "2023-07-01T08:15:00.0", 0, 0], ["2023-07-01T08:15:00.0", + "2023-07-01T08:30:00.0", 0, 0], ["2023-07-01T08:30:00.0", "2023-07-01T08:45:00.0", + 0, 0], ["2023-07-01T08:45:00.0", "2023-07-01T09:00:00.0", 0, 0], ["2023-07-01T09:00:00.0", + "2023-07-01T09:15:00.0", 0, 0], ["2023-07-01T09:15:00.0", "2023-07-01T09:30:00.0", + 0, 0], ["2023-07-01T09:30:00.0", "2023-07-01T09:45:00.0", 0, 0], ["2023-07-01T09:45:00.0", + "2023-07-01T10:00:00.0", 0, 0], ["2023-07-01T10:00:00.0", "2023-07-01T10:15:00.0", + 0, 0], ["2023-07-01T10:15:00.0", "2023-07-01T10:30:00.0", 0, 0], ["2023-07-01T10:30:00.0", + "2023-07-01T10:45:00.0", 0, 0], ["2023-07-01T10:45:00.0", "2023-07-01T11:00:00.0", + 0, 0], ["2023-07-01T11:00:00.0", "2023-07-01T11:15:00.0", 0, 0], ["2023-07-01T11:15:00.0", + "2023-07-01T11:30:00.0", 0, 1], ["2023-07-01T11:30:00.0", "2023-07-01T11:45:00.0", + 0, 0], ["2023-07-01T11:45:00.0", "2023-07-01T12:00:00.0", 1, 0], ["2023-07-01T12:00:00.0", + "2023-07-01T12:15:00.0", 0, 0], ["2023-07-01T12:15:00.0", "2023-07-01T12:30:00.0", + 0, 0], ["2023-07-01T12:30:00.0", "2023-07-01T12:45:00.0", 0, 0], ["2023-07-01T12:45:00.0", + "2023-07-01T13:00:00.0", 1, 1], ["2023-07-01T13:00:00.0", "2023-07-01T13:15:00.0", + 0, 0], ["2023-07-01T13:15:00.0", "2023-07-01T13:30:00.0", 0, 0], ["2023-07-01T13:30:00.0", + "2023-07-01T13:45:00.0", 0, 1], ["2023-07-01T13:45:00.0", "2023-07-01T14:00:00.0", + 0, 0], ["2023-07-01T14:00:00.0", "2023-07-01T14:15:00.0", 1, 2], ["2023-07-01T14:15:00.0", + "2023-07-01T14:30:00.0", 0, 0], ["2023-07-01T14:30:00.0", "2023-07-01T14:45:00.0", + 0, 0], ["2023-07-01T14:45:00.0", "2023-07-01T15:00:00.0", 0, 0], ["2023-07-01T15:00:00.0", + "2023-07-01T15:15:00.0", 0, 0], ["2023-07-01T15:15:00.0", "2023-07-01T15:30:00.0", + 0, 0], ["2023-07-01T15:30:00.0", "2023-07-01T15:45:00.0", 1, 0], ["2023-07-01T15:45:00.0", + "2023-07-01T16:00:00.0", 0, 0], ["2023-07-01T16:00:00.0", "2023-07-01T16:15:00.0", + 0, 0], ["2023-07-01T16:15:00.0", "2023-07-01T16:30:00.0", 0, 0], ["2023-07-01T16:30:00.0", + "2023-07-01T16:45:00.0", 0, 0], ["2023-07-01T16:45:00.0", "2023-07-01T17:00:00.0", + 0, 0], ["2023-07-01T17:00:00.0", "2023-07-01T17:15:00.0", 3, 1], ["2023-07-01T17:15:00.0", + "2023-07-01T17:30:00.0", 0, 0], ["2023-07-01T17:30:00.0", "2023-07-01T17:45:00.0", + 0, 0], ["2023-07-01T17:45:00.0", "2023-07-01T18:00:00.0", 0, 0], ["2023-07-01T18:00:00.0", + "2023-07-01T18:15:00.0", 0, 0], ["2023-07-01T18:15:00.0", "2023-07-01T18:30:00.0", + 0, 0], ["2023-07-01T18:30:00.0", "2023-07-01T18:45:00.0", 0, 0], ["2023-07-01T18:45:00.0", + "2023-07-01T19:00:00.0", 1, 0], ["2023-07-01T19:00:00.0", "2023-07-01T19:15:00.0", + 0, 0], ["2023-07-01T19:15:00.0", "2023-07-01T19:30:00.0", 0, 1], ["2023-07-01T19:30:00.0", + "2023-07-01T19:45:00.0", 0, 4], ["2023-07-01T19:45:00.0", "2023-07-01T20:00:00.0", + 0, 0], ["2023-07-01T20:00:00.0", "2023-07-01T20:15:00.0", 0, 0], ["2023-07-01T20:15:00.0", + "2023-07-01T20:30:00.0", 0, 0], ["2023-07-01T20:30:00.0", "2023-07-01T20:45:00.0", + 0, 0], ["2023-07-01T20:45:00.0", "2023-07-01T21:00:00.0", 0, 0], ["2023-07-01T21:00:00.0", + "2023-07-01T21:15:00.0", 1, 2], ["2023-07-01T21:15:00.0", "2023-07-01T21:30:00.0", + 0, 0], ["2023-07-01T21:30:00.0", "2023-07-01T21:45:00.0", 0, 0], ["2023-07-01T21:45:00.0", + "2023-07-01T22:00:00.0", 0, 0], ["2023-07-01T22:00:00.0", "2023-07-01T22:15:00.0", + 0, 0], ["2023-07-01T22:15:00.0", "2023-07-01T22:30:00.0", 0, 0], ["2023-07-01T22:30:00.0", + "2023-07-01T22:45:00.0", 0, 0], ["2023-07-01T22:45:00.0", "2023-07-01T23:00:00.0", + 0, 0], ["2023-07-01T23:00:00.0", "2023-07-01T23:15:00.0", 0, 0], ["2023-07-01T23:15:00.0", + "2023-07-01T23:30:00.0", 0, 0], ["2023-07-01T23:30:00.0", "2023-07-01T23:45:00.0", + 0, 0], ["2023-07-01T23:45:00.0", "2023-07-02T00:00:00.0", 2, 0], ["2023-07-02T00:00:00.0", + "2023-07-02T00:15:00.0", 0, 0], ["2023-07-02T00:15:00.0", "2023-07-02T00:30:00.0", + 2, 0], ["2023-07-02T00:30:00.0", "2023-07-02T00:45:00.0", 0, 0], ["2023-07-02T00:45:00.0", + "2023-07-02T01:00:00.0", 2, 2], ["2023-07-02T01:00:00.0", "2023-07-02T01:15:00.0", + 1, 1], ["2023-07-02T01:15:00.0", "2023-07-02T01:30:00.0", 0, 0], ["2023-07-02T01:30:00.0", + "2023-07-02T01:45:00.0", 0, 2], ["2023-07-02T01:45:00.0", "2023-07-02T02:00:00.0", + 4, 2], ["2023-07-02T02:00:00.0", "2023-07-02T02:15:00.0", 0, 0], ["2023-07-02T02:15:00.0", + "2023-07-02T02:30:00.0", 0, 0], ["2023-07-02T02:30:00.0", "2023-07-02T02:45:00.0", + 0, 0], ["2023-07-02T02:45:00.0", "2023-07-02T03:00:00.0", 0, 0], ["2023-07-02T03:00:00.0", + "2023-07-02T03:15:00.0", 0, 0], ["2023-07-02T03:15:00.0", "2023-07-02T03:30:00.0", + 0, 0], ["2023-07-02T03:30:00.0", "2023-07-02T03:45:00.0", 0, 1], ["2023-07-02T03:45:00.0", + "2023-07-02T04:00:00.0", 4, 1], ["2023-07-02T04:00:00.0", "2023-07-02T04:15:00.0", + 0, 0], ["2023-07-02T04:15:00.0", "2023-07-02T04:30:00.0", 0, 0], ["2023-07-02T04:30:00.0", + "2023-07-02T04:45:00.0", 0, 0], ["2023-07-02T04:45:00.0", "2023-07-02T05:00:00.0", + 0, 0], ["2023-07-02T05:00:00.0", "2023-07-02T05:15:00.0", 0, 2], ["2023-07-02T05:15:00.0", + "2023-07-02T05:30:00.0", 0, 0], ["2023-07-02T05:30:00.0", "2023-07-02T05:45:00.0", + 5, 5], ["2023-07-02T05:45:00.0", "2023-07-02T06:00:00.0", 0, 0]]}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8740a6ef41463e-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 04:00:54 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=lxY7Q%2BGKPaXN2DpJu8%2BCjHI6CMPtwvhQDlFrjA09aAG4aIAy2bUBICGsi4T688SrIsoayL3lZGWnqNIjzdm0ybZ9Tlry3M30rNTNppkI1wNRZIkQj3NfukAtdH0SDXkaTpB%2F5hpM7g%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_heart_rates.yaml b/tests/cassettes/test_heart_rates.yaml new file mode 100644 index 0000000..56b356e --- /dev/null +++ b/tests/cassettes/test_heart_rates.yaml @@ -0,0 +1,423 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a4dfd38ceb6ee-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 12:54:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=La2NeCtpgizXPwqTA6hQIqHxHZp3Q7NKoQpteVkisyVSSERbgN4lDUZ5tc2dxWena37ZPgY12J0dvwsfCGcoI9A1Y2s%2F%2FLMzXlGcsUBNyuYhaYlcBiD%2BBRQKODoqJCYIrgUi5GoFmA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a4dfdf980b6e5-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 12:54:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=I5KMiCopdLs1oRVeXXMDAPzqBe%2BvuJTYtO%2BiQ3BjpTVhWpMicJVwZ%2BQ6MKe2rMgrLFD%2FcnikpBSUW7ePlKyy2IKZJSMzxgCzIIOemxy8o70roRlr9CH2xD7rMqhMEpRsErmGVmDyaQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/wellness-service/wellness/dailyHeartRate/mtamizi?date=2023-07-01 + response: + body: + string: '{"userProfilePK": 2591602, "calendarDate": "2023-07-01", "startTimestampGMT": + "2023-07-01T06:00:00.0", "endTimestampGMT": "2023-07-02T06:00:00.0", "startTimestampLocal": + "2023-07-01T00:00:00.0", "endTimestampLocal": "2023-07-02T00:00:00.0", "maxHeartRate": + 106, "minHeartRate": 49, "restingHeartRate": 51, "lastSevenDaysAvgRestingHeartRate": + 49, "heartRateValueDescriptors": [{"key": "timestamp", "index": 0}, {"key": + "heartrate", "index": 1}], "heartRateValues": [[1688191200000, 56], [1688191320000, + 57], [1688191440000, 56], [1688191560000, 56], [1688191680000, 57], [1688191800000, + 59], [1688191920000, 58], [1688192040000, 59], [1688192160000, 60], [1688192280000, + 57], [1688192400000, 57], [1688192520000, 60], [1688192640000, 59], [1688192760000, + 58], [1688192880000, 58], [1688193000000, 59], [1688193120000, 59], [1688193240000, + 61], [1688193360000, 58], [1688193480000, 58], [1688193600000, 58], [1688193720000, + 58], [1688193840000, 59], [1688193960000, 58], [1688194080000, 57], [1688194200000, + 58], [1688194320000, 58], [1688194440000, 57], [1688194560000, 60], [1688194680000, + 62], [1688194800000, 57], [1688194920000, 57], [1688195040000, 56], [1688195160000, + 55], [1688195280000, 55], [1688195400000, 55], [1688195520000, 54], [1688195640000, + 54], [1688195760000, 54], [1688195880000, 55], [1688196000000, 55], [1688196120000, + 54], [1688196240000, 55], [1688196360000, 54], [1688196480000, 55], [1688196600000, + 54], [1688196720000, 54], [1688196840000, 54], [1688196960000, 54], [1688197080000, + 54], [1688197200000, 55], [1688197320000, 55], [1688197440000, 55], [1688197560000, + 55], [1688197680000, 53], [1688197800000, 55], [1688197920000, 54], [1688198040000, + 54], [1688198160000, 56], [1688198280000, 54], [1688198400000, 54], [1688198520000, + 54], [1688198640000, 55], [1688198760000, 54], [1688198880000, 54], [1688199000000, + 54], [1688199120000, 55], [1688199240000, 55], [1688199360000, 55], [1688199480000, + 55], [1688199600000, 55], [1688199720000, 54], [1688199840000, 54], [1688199960000, + 54], [1688200080000, 52], [1688200200000, 53], [1688200320000, 53], [1688200440000, + 53], [1688200560000, 53], [1688200680000, 53], [1688200800000, 53], [1688200920000, + 53], [1688201040000, 53], [1688201160000, 53], [1688201280000, 53], [1688201400000, + 53], [1688201520000, 53], [1688201640000, 52], [1688201760000, 53], [1688201880000, + 53], [1688202000000, 52], [1688202120000, 53], [1688202240000, 54], [1688202360000, + 52], [1688202480000, 53], [1688202600000, 51], [1688202720000, 52], [1688202840000, + 52], [1688202960000, 53], [1688203080000, 52], [1688203200000, 52], [1688203320000, + 52], [1688203440000, 52], [1688203560000, 51], [1688203680000, 51], [1688203800000, + 50], [1688203920000, 51], [1688204040000, 52], [1688204160000, 52], [1688204280000, + 52], [1688204400000, 53], [1688204520000, 53], [1688204640000, 51], [1688204760000, + 53], [1688204880000, 51], [1688205000000, 51], [1688205120000, 51], [1688205240000, + 51], [1688205360000, 51], [1688205480000, 51], [1688205600000, 51], [1688205720000, + 51], [1688205840000, 53], [1688205960000, 51], [1688206080000, 52], [1688206200000, + 53], [1688206320000, 52], [1688206440000, 52], [1688206560000, 52], [1688206680000, + 52], [1688206800000, 52], [1688206920000, 53], [1688207040000, 52], [1688207160000, + 53], [1688207280000, 52], [1688207400000, 52], [1688207520000, 54], [1688207640000, + 53], [1688207760000, 52], [1688207880000, 53], [1688208000000, 52], [1688208120000, + 53], [1688208240000, 53], [1688208360000, 55], [1688208480000, 53], [1688208600000, + 52], [1688208720000, 50], [1688208840000, 52], [1688208960000, 52], [1688209080000, + 54], [1688209200000, 49], [1688209320000, null], [1688209440000, 67], [1688209560000, + 53], [1688209680000, 51], [1688209800000, 52], [1688209920000, 51], [1688210040000, + 51], [1688210160000, 51], [1688210280000, 52], [1688210400000, 52], [1688210520000, + 52], [1688210640000, 54], [1688210760000, 56], [1688210880000, 59], [1688211000000, + 75], [1688211120000, 79], [1688211240000, 84], [1688211360000, 90], [1688211480000, + 84], [1688211600000, 77], [1688211720000, 88], [1688211840000, 78], [1688211960000, + 83], [1688212080000, 62], [1688212200000, 56], [1688212320000, 53], [1688212440000, + 53], [1688212560000, 53], [1688212680000, 55], [1688212800000, 56], [1688212920000, + 59], [1688213040000, 55], [1688213160000, 60], [1688213280000, 57], [1688213400000, + 58], [1688213520000, 56], [1688213640000, 56], [1688213760000, 57], [1688213880000, + 55], [1688214000000, 55], [1688214120000, 57], [1688214240000, 58], [1688214360000, + 69], [1688214480000, 72], [1688214600000, 78], [1688214720000, 79], [1688214840000, + 77], [1688214960000, 72], [1688215080000, 75], [1688215200000, 77], [1688215320000, + 72], [1688215440000, 75], [1688215560000, 74], [1688215680000, 77], [1688215800000, + 75], [1688215920000, 73], [1688216040000, 77], [1688216160000, 73], [1688216280000, + 72], [1688216400000, 78], [1688216520000, 78], [1688216640000, 72], [1688216760000, + 73], [1688216880000, 75], [1688217000000, 77], [1688217120000, 71], [1688217240000, + 74], [1688217360000, 74], [1688217480000, 72], [1688217600000, 73], [1688217720000, + 71], [1688217840000, 74], [1688217960000, 72], [1688218080000, 75], [1688218200000, + 78], [1688218320000, 73], [1688218440000, 89], [1688218560000, 96], [1688218680000, + 102], [1688218800000, 91], [1688218920000, 91], [1688219040000, 87], [1688219160000, + 81], [1688219280000, 71], [1688219400000, 73], [1688219520000, 84], [1688219640000, + 85], [1688219760000, 96], [1688219880000, 72], [1688220000000, 89], [1688220120000, + 75], [1688220240000, 74], [1688220360000, 70], [1688220480000, 75], [1688220600000, + 75], [1688220720000, 90], [1688220840000, 94], [1688220960000, 78], [1688221080000, + 85], [1688221200000, 93], [1688221320000, 90], [1688221440000, 96], [1688221560000, + 103], [1688221680000, 97], [1688221800000, 92], [1688221920000, 92], [1688222040000, + 86], [1688222160000, 84], [1688222280000, 83], [1688222400000, 86], [1688222520000, + 72], [1688222640000, 65], [1688222760000, 63], [1688222880000, 61], [1688223000000, + 70], [1688223120000, 75], [1688223240000, 77], [1688223360000, 75], [1688223480000, + 70], [1688223600000, 73], [1688223720000, 77], [1688223840000, 80], [1688223960000, + 78], [1688224080000, 70], [1688224200000, 77], [1688224320000, 76], [1688224440000, + 79], [1688224560000, 77], [1688224680000, 74], [1688224800000, 75], [1688224920000, + 72], [1688225040000, 71], [1688225160000, 70], [1688225280000, 76], [1688225400000, + 70], [1688225520000, 75], [1688225640000, 80], [1688225760000, 78], [1688225880000, + 80], [1688226000000, 80], [1688226120000, 76], [1688226240000, 81], [1688226360000, + 81], [1688226480000, 84], [1688226600000, 93], [1688226720000, 90], [1688226840000, + 93], [1688226960000, 77], [1688227080000, 68], [1688227200000, 67], [1688227320000, + 90], [1688227440000, 85], [1688227560000, 83], [1688227680000, 83], [1688227800000, + 77], [1688227920000, 74], [1688228040000, 69], [1688228160000, 76], [1688228280000, + 62], [1688228400000, 74], [1688228520000, 61], [1688228640000, 61], [1688228760000, + 65], [1688228880000, 68], [1688229000000, 64], [1688229120000, 63], [1688229240000, + 74], [1688229360000, 76], [1688229480000, 73], [1688229600000, 77], [1688229720000, + 77], [1688229840000, 77], [1688229960000, 73], [1688230080000, 78], [1688230200000, + 77], [1688230320000, 79], [1688230440000, 86], [1688230560000, 84], [1688230680000, + 77], [1688230800000, 80], [1688230920000, 73], [1688231040000, 59], [1688231160000, + 54], [1688231280000, 55], [1688231400000, 68], [1688231520000, 76], [1688231640000, + 62], [1688231760000, 67], [1688231880000, 64], [1688232000000, 61], [1688232120000, + 62], [1688232240000, 66], [1688232360000, 66], [1688232480000, 64], [1688232600000, + 66], [1688232720000, 63], [1688232840000, 73], [1688232960000, 68], [1688233080000, + 65], [1688233200000, 67], [1688233320000, 67], [1688233440000, 68], [1688233560000, + 67], [1688233680000, 71], [1688233800000, 68], [1688233920000, 70], [1688234040000, + 69], [1688234160000, 69], [1688234280000, 65], [1688234400000, 70], [1688234520000, + 66], [1688234640000, 69], [1688234760000, 71], [1688234880000, 66], [1688235000000, + 69], [1688235120000, 67], [1688235240000, 67], [1688235360000, 67], [1688235480000, + 72], [1688235600000, 71], [1688235720000, 76], [1688235840000, 74], [1688235960000, + 69], [1688236080000, 71], [1688236200000, 70], [1688236320000, 69], [1688236440000, + 73], [1688236560000, 73], [1688236680000, 73], [1688236800000, 71], [1688236920000, + 72], [1688237040000, 74], [1688237160000, 74], [1688237280000, 73], [1688237400000, + 71], [1688237520000, 72], [1688237640000, 75], [1688237760000, 73], [1688237880000, + 79], [1688238000000, null], [1688238960000, 84], [1688239080000, null], [1688239440000, + 86], [1688239560000, 91], [1688239680000, 74], [1688239800000, 62], [1688239920000, + 77], [1688240040000, 84], [1688240160000, 83], [1688240280000, 73], [1688240400000, + 89], [1688240520000, 88], [1688240640000, 81], [1688240760000, 87], [1688240880000, + 85], [1688241000000, 94], [1688241120000, 93], [1688241240000, 95], [1688241360000, + 90], [1688241480000, 70], [1688241600000, 60], [1688241720000, 57], [1688241840000, + 60], [1688241960000, 61], [1688242080000, 67], [1688242200000, 64], [1688242320000, + 62], [1688242440000, 62], [1688242560000, 63], [1688242680000, 66], [1688242800000, + 74], [1688242920000, 75], [1688243040000, 86], [1688243160000, 78], [1688243280000, + 74], [1688243400000, 65], [1688243520000, 59], [1688243640000, 61], [1688243760000, + 67], [1688243880000, 64], [1688244000000, 66], [1688244120000, 63], [1688244240000, + 63], [1688244360000, 65], [1688244480000, 70], [1688244600000, 66], [1688244720000, + 65], [1688244840000, 85], [1688244960000, 67], [1688245080000, 60], [1688245200000, + 68], [1688245320000, 75], [1688245440000, 77], [1688245560000, 76], [1688245680000, + 76], [1688245800000, 75], [1688245920000, 70], [1688246040000, 70], [1688246160000, + 71], [1688246280000, 70], [1688246400000, 72], [1688246520000, 67], [1688246640000, + 69], [1688246760000, 70], [1688246880000, 71], [1688247000000, 69], [1688247120000, + 67], [1688247240000, 69], [1688247360000, 67], [1688247480000, 71], [1688247600000, + 66], [1688247720000, 85], [1688247840000, 91], [1688247960000, 84], [1688248080000, + 89], [1688248200000, 77], [1688248320000, 85], [1688248440000, 94], [1688248560000, + 106], [1688248680000, 106], [1688248800000, 87], [1688248920000, 71], [1688249040000, + 69], [1688249160000, 78], [1688249280000, 84], [1688249400000, 87], [1688249520000, + 86], [1688249640000, 84], [1688249760000, 84], [1688249880000, 78], [1688250000000, + 85], [1688250120000, 89], [1688250240000, 92], [1688250360000, 91], [1688250480000, + 87], [1688250600000, 85], [1688250720000, 85], [1688250840000, 85], [1688250960000, + 83], [1688251080000, 81], [1688251200000, 88], [1688251320000, 91], [1688251440000, + 87], [1688251560000, 91], [1688251680000, 86], [1688251800000, 85], [1688251920000, + 77], [1688252040000, 78], [1688252160000, 86], [1688252280000, 79], [1688252400000, + 79], [1688252520000, 89], [1688252640000, 82], [1688252760000, 79], [1688252880000, + 77], [1688253000000, 82], [1688253120000, 76], [1688253240000, 79], [1688253360000, + 83], [1688253480000, 80], [1688253600000, 82], [1688253720000, 73], [1688253840000, + 72], [1688253960000, 73], [1688254080000, 76], [1688254200000, 76], [1688254320000, + 94], [1688254440000, 94], [1688254560000, 84], [1688254680000, 85], [1688254800000, + 90], [1688254920000, 94], [1688255040000, 87], [1688255160000, 80], [1688255280000, + 85], [1688255400000, 86], [1688255520000, 97], [1688255640000, 96], [1688255760000, + 85], [1688255880000, 76], [1688256000000, 71], [1688256120000, 75], [1688256240000, + 74], [1688256360000, 74], [1688256480000, 70], [1688256600000, 69], [1688256720000, + 69], [1688256840000, 69], [1688256960000, 70], [1688257080000, 73], [1688257200000, + 73], [1688257320000, 74], [1688257440000, 80], [1688257560000, 94], [1688257680000, + 102], [1688257800000, 85], [1688257920000, 74], [1688258040000, 71], [1688258160000, + 71], [1688258280000, 70], [1688258400000, 72], [1688258520000, 69], [1688258640000, + 70], [1688258760000, 69], [1688258880000, 69], [1688259000000, 71], [1688259120000, + 88], [1688259240000, 93], [1688259360000, 82], [1688259480000, 80], [1688259600000, + 76], [1688259720000, 73], [1688259840000, 93], [1688259960000, 84], [1688260080000, + 70], [1688260200000, 67], [1688260320000, 72], [1688260440000, 76], [1688260560000, + 71], [1688260680000, 70], [1688260800000, 73], [1688260920000, 71], [1688261040000, + 71], [1688261160000, 70], [1688261280000, 74], [1688261400000, 78], [1688261520000, + 74], [1688261640000, 70], [1688261760000, 72], [1688261880000, 78], [1688262000000, + 97], [1688262120000, 96], [1688262240000, 101], [1688262360000, 85], [1688262480000, + 88], [1688262600000, 93], [1688262720000, 72], [1688262840000, 84], [1688262960000, + 92], [1688263080000, 96], [1688263200000, 88], [1688263320000, 81], [1688263440000, + 79], [1688263560000, 76], [1688263680000, 78], [1688263800000, 79], [1688263920000, + 80], [1688264040000, 78], [1688264160000, 77], [1688264280000, 84], [1688264400000, + 77], [1688264520000, 80], [1688264640000, 77], [1688264760000, 78], [1688264880000, + 77], [1688265000000, 89], [1688265120000, 88], [1688265240000, 85], [1688265360000, + 80], [1688265480000, 73], [1688265600000, 76], [1688265720000, 74], [1688265840000, + 76], [1688265960000, 77], [1688266080000, 77], [1688266200000, 79], [1688266320000, + 75], [1688266440000, 74], [1688266560000, 77], [1688266680000, 78], [1688266800000, + 78], [1688266920000, 80], [1688267040000, 76], [1688267160000, 77], [1688267280000, + 75], [1688267400000, 74], [1688267520000, 75], [1688267640000, 70], [1688267760000, + 76], [1688267880000, 76], [1688268000000, 75], [1688268120000, 75], [1688268240000, + 72], [1688268360000, 75], [1688268480000, 74], [1688268600000, 81], [1688268720000, + 82], [1688268840000, 81], [1688268960000, 77], [1688269080000, 73], [1688269200000, + 89], [1688269320000, 95], [1688269440000, 94], [1688269560000, 94], [1688269680000, + 82], [1688269800000, 81], [1688269920000, 82], [1688270040000, 85], [1688270160000, + 81], [1688270280000, 77], [1688270400000, 71], [1688270520000, 72], [1688270640000, + 70], [1688270760000, 70], [1688270880000, 72], [1688271000000, 73], [1688271120000, + 70], [1688271240000, 74], [1688271360000, 68], [1688271480000, 71], [1688271600000, + 71], [1688271720000, 72], [1688271840000, 76], [1688271960000, 78], [1688272080000, + 62], [1688272200000, 60], [1688272320000, 62], [1688272440000, 62], [1688272560000, + 65], [1688272680000, 64], [1688272800000, 66], [1688272920000, 67], [1688273040000, + 65], [1688273160000, 66], [1688273280000, 63], [1688273400000, 64], [1688273520000, + 64], [1688273640000, 66], [1688273760000, 63], [1688273880000, 63], [1688274000000, + 62], [1688274120000, 64], [1688274240000, 86], [1688274360000, 83], [1688274480000, + 81], [1688274600000, 78], [1688274720000, 85], [1688274840000, 83], [1688274960000, + 80], [1688275080000, 79], [1688275200000, 85], [1688275320000, 86], [1688275440000, + 82], [1688275560000, 84], [1688275680000, 70], [1688275800000, 86], [1688275920000, + 80], [1688276040000, 70], [1688276160000, 81], [1688276280000, 77], [1688276400000, + 86], [1688276520000, 90], [1688276640000, 64], [1688276760000, 62], [1688276880000, + 65], [1688277000000, 74], [1688277120000, 65], [1688277240000, 72], [1688277360000, + 56], [1688277480000, 56]]}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a4dfee830b6e8-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 12:54:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=RtawwZ3pSW1TMssDM4vc6f7eVeb9oADwxK%2BINk45Vx4e1AyguWYrznt%2FoDCl6UEkpB1NwQ%2FFbPxambaMTGURI7ZV6N4U6yGHHCKvskFW3RdDdQ1aSXBdM1vpM%2BApri80AajDX17GxQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_hrv_data.yaml b/tests/cassettes/test_hrv_data.yaml new file mode 100644 index 0000000..9750b91 --- /dev/null +++ b/tests/cassettes/test_hrv_data.yaml @@ -0,0 +1,318 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8c22b8fd5db6ed-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 18:14:17 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=0E77t2nW5dGJbcmzeOjPJoIjH2646y1L2BeBzRVSPirgt6bd2fNJbl8cpsSu%2Bvb0XSQ0E4kbICTNiK%2FJnEhNsgwkeHWFbjC7APT867Vf%2FdAInYViBoc7S1CMJyZtmBB2Fybh1dz32g%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8c22baef2146e9-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 18:14:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=%2BZjeDtpfTSyeEJtm6VjqgfKiqPie8kaSR1fdapEWVOUg1%2BjoTebr%2FmIk7mri7ypjXTL2A8ZX%2Bi3OLErVyTv6HDuUNpJw9i7LLALaMQoidzMGEwUDfKsQQG5MCrY06CT0SYZxun%2BdSw%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/hrv-service/hrv/2023-07-01 + response: + body: + string: '{"userProfilePk": 2591602, "hrvSummary": {"calendarDate": "2023-07-01", + "weeklyAvg": 43, "lastNightAvg": 43, "lastNight5MinHigh": 60, "baseline": + {"lowUpper": 35, "balancedLow": 38, "balancedUpper": 52, "markerValue": 0.42855835}, + "status": "BALANCED", "feedbackPhrase": "HRV_BALANCED_8", "createTimeStamp": + "2023-07-01T12:27:14.85"}, "hrvReadings": [{"hrvValue": 44, "readingTimeGMT": + "2023-07-01T06:44:41.0", "readingTimeLocal": "2023-07-01T00:44:41.0"}, {"hrvValue": + 39, "readingTimeGMT": "2023-07-01T06:49:41.0", "readingTimeLocal": "2023-07-01T00:49:41.0"}, + {"hrvValue": 49, "readingTimeGMT": "2023-07-01T06:54:41.0", "readingTimeLocal": + "2023-07-01T00:54:41.0"}, {"hrvValue": 55, "readingTimeGMT": "2023-07-01T06:59:41.0", + "readingTimeLocal": "2023-07-01T00:59:41.0"}, {"hrvValue": 46, "readingTimeGMT": + "2023-07-01T07:04:41.0", "readingTimeLocal": "2023-07-01T01:04:41.0"}, {"hrvValue": + 42, "readingTimeGMT": "2023-07-01T07:09:41.0", "readingTimeLocal": "2023-07-01T01:09:41.0"}, + {"hrvValue": 56, "readingTimeGMT": "2023-07-01T07:14:41.0", "readingTimeLocal": + "2023-07-01T01:14:41.0"}, {"hrvValue": 51, "readingTimeGMT": "2023-07-01T07:19:41.0", + "readingTimeLocal": "2023-07-01T01:19:41.0"}, {"hrvValue": 42, "readingTimeGMT": + "2023-07-01T07:24:41.0", "readingTimeLocal": "2023-07-01T01:24:41.0"}, {"hrvValue": + 49, "readingTimeGMT": "2023-07-01T07:29:41.0", "readingTimeLocal": "2023-07-01T01:29:41.0"}, + {"hrvValue": 43, "readingTimeGMT": "2023-07-01T07:34:41.0", "readingTimeLocal": + "2023-07-01T01:34:41.0"}, {"hrvValue": 40, "readingTimeGMT": "2023-07-01T07:39:41.0", + "readingTimeLocal": "2023-07-01T01:39:41.0"}, {"hrvValue": 45, "readingTimeGMT": + "2023-07-01T07:44:41.0", "readingTimeLocal": "2023-07-01T01:44:41.0"}, {"hrvValue": + 42, "readingTimeGMT": "2023-07-01T07:49:41.0", "readingTimeLocal": "2023-07-01T01:49:41.0"}, + {"hrvValue": 45, "readingTimeGMT": "2023-07-01T07:54:41.0", "readingTimeLocal": + "2023-07-01T01:54:41.0"}, {"hrvValue": 42, "readingTimeGMT": "2023-07-01T07:59:41.0", + "readingTimeLocal": "2023-07-01T01:59:41.0"}, {"hrvValue": 38, "readingTimeGMT": + "2023-07-01T08:04:41.0", "readingTimeLocal": "2023-07-01T02:04:41.0"}, {"hrvValue": + 39, "readingTimeGMT": "2023-07-01T08:09:41.0", "readingTimeLocal": "2023-07-01T02:09:41.0"}, + {"hrvValue": 45, "readingTimeGMT": "2023-07-01T08:14:41.0", "readingTimeLocal": + "2023-07-01T02:14:41.0"}, {"hrvValue": 40, "readingTimeGMT": "2023-07-01T08:19:41.0", + "readingTimeLocal": "2023-07-01T02:19:41.0"}, {"hrvValue": 30, "readingTimeGMT": + "2023-07-01T08:24:41.0", "readingTimeLocal": "2023-07-01T02:24:41.0"}, {"hrvValue": + 36, "readingTimeGMT": "2023-07-01T08:29:41.0", "readingTimeLocal": "2023-07-01T02:29:41.0"}, + {"hrvValue": 27, "readingTimeGMT": "2023-07-01T08:34:41.0", "readingTimeLocal": + "2023-07-01T02:34:41.0"}, {"hrvValue": 33, "readingTimeGMT": "2023-07-01T08:39:41.0", + "readingTimeLocal": "2023-07-01T02:39:41.0"}, {"hrvValue": 29, "readingTimeGMT": + "2023-07-01T08:44:41.0", "readingTimeLocal": "2023-07-01T02:44:41.0"}, {"hrvValue": + 30, "readingTimeGMT": "2023-07-01T08:49:41.0", "readingTimeLocal": "2023-07-01T02:49:41.0"}, + {"hrvValue": 29, "readingTimeGMT": "2023-07-01T08:54:41.0", "readingTimeLocal": + "2023-07-01T02:54:41.0"}, {"hrvValue": 37, "readingTimeGMT": "2023-07-01T08:59:41.0", + "readingTimeLocal": "2023-07-01T02:59:41.0"}, {"hrvValue": 47, "readingTimeGMT": + "2023-07-01T09:04:41.0", "readingTimeLocal": "2023-07-01T03:04:41.0"}, {"hrvValue": + 39, "readingTimeGMT": "2023-07-01T09:09:41.0", "readingTimeLocal": "2023-07-01T03:09:41.0"}, + {"hrvValue": 38, "readingTimeGMT": "2023-07-01T09:14:41.0", "readingTimeLocal": + "2023-07-01T03:14:41.0"}, {"hrvValue": 42, "readingTimeGMT": "2023-07-01T09:19:41.0", + "readingTimeLocal": "2023-07-01T03:19:41.0"}, {"hrvValue": 35, "readingTimeGMT": + "2023-07-01T09:24:41.0", "readingTimeLocal": "2023-07-01T03:24:41.0"}, {"hrvValue": + 55, "readingTimeGMT": "2023-07-01T09:29:41.0", "readingTimeLocal": "2023-07-01T03:29:41.0"}, + {"hrvValue": 50, "readingTimeGMT": "2023-07-01T09:34:41.0", "readingTimeLocal": + "2023-07-01T03:34:41.0"}, {"hrvValue": 41, "readingTimeGMT": "2023-07-01T09:39:41.0", + "readingTimeLocal": "2023-07-01T03:39:41.0"}, {"hrvValue": 57, "readingTimeGMT": + "2023-07-01T09:44:41.0", "readingTimeLocal": "2023-07-01T03:44:41.0"}, {"hrvValue": + 44, "readingTimeGMT": "2023-07-01T09:49:41.0", "readingTimeLocal": "2023-07-01T03:49:41.0"}, + {"hrvValue": 36, "readingTimeGMT": "2023-07-01T09:54:41.0", "readingTimeLocal": + "2023-07-01T03:54:41.0"}, {"hrvValue": 41, "readingTimeGMT": "2023-07-01T09:59:41.0", + "readingTimeLocal": "2023-07-01T03:59:41.0"}, {"hrvValue": 47, "readingTimeGMT": + "2023-07-01T10:04:41.0", "readingTimeLocal": "2023-07-01T04:04:41.0"}, {"hrvValue": + 47, "readingTimeGMT": "2023-07-01T10:09:41.0", "readingTimeLocal": "2023-07-01T04:09:41.0"}, + {"hrvValue": 40, "readingTimeGMT": "2023-07-01T10:14:41.0", "readingTimeLocal": + "2023-07-01T04:14:41.0"}, {"hrvValue": 28, "readingTimeGMT": "2023-07-01T10:19:41.0", + "readingTimeLocal": "2023-07-01T04:19:41.0"}, {"hrvValue": 33, "readingTimeGMT": + "2023-07-01T10:24:41.0", "readingTimeLocal": "2023-07-01T04:24:41.0"}, {"hrvValue": + 37, "readingTimeGMT": "2023-07-01T10:29:41.0", "readingTimeLocal": "2023-07-01T04:29:41.0"}, + {"hrvValue": 50, "readingTimeGMT": "2023-07-01T10:34:41.0", "readingTimeLocal": + "2023-07-01T04:34:41.0"}, {"hrvValue": 37, "readingTimeGMT": "2023-07-01T10:39:41.0", + "readingTimeLocal": "2023-07-01T04:39:41.0"}, {"hrvValue": 41, "readingTimeGMT": + "2023-07-01T10:44:41.0", "readingTimeLocal": "2023-07-01T04:44:41.0"}, {"hrvValue": + 36, "readingTimeGMT": "2023-07-01T10:49:41.0", "readingTimeLocal": "2023-07-01T04:49:41.0"}, + {"hrvValue": 60, "readingTimeGMT": "2023-07-01T10:54:41.0", "readingTimeLocal": + "2023-07-01T04:54:41.0"}, {"hrvValue": 51, "readingTimeGMT": "2023-07-01T10:59:41.0", + "readingTimeLocal": "2023-07-01T04:59:41.0"}, {"hrvValue": 46, "readingTimeGMT": + "2023-07-01T11:04:41.0", "readingTimeLocal": "2023-07-01T05:04:41.0"}, {"hrvValue": + 37, "readingTimeGMT": "2023-07-01T11:09:41.0", "readingTimeLocal": "2023-07-01T05:09:41.0"}, + {"hrvValue": 36, "readingTimeGMT": "2023-07-01T11:14:41.0", "readingTimeLocal": + "2023-07-01T05:14:41.0"}, {"hrvValue": 33, "readingTimeGMT": "2023-07-01T11:19:41.0", + "readingTimeLocal": "2023-07-01T05:19:41.0"}, {"hrvValue": 50, "readingTimeGMT": + "2023-07-01T11:24:41.0", "readingTimeLocal": "2023-07-01T05:24:41.0"}], "startTimestampGMT": + "2023-07-01T06:40:00.0", "endTimestampGMT": "2023-07-01T11:24:41.0", "startTimestampLocal": + "2023-07-01T00:40:00.0", "endTimestampLocal": "2023-07-01T05:24:41.0", "sleepStartTimestampGMT": + "2023-07-01T06:40:00.0", "sleepEndTimestampGMT": "2023-07-01T11:26:00.0", + "sleepStartTimestampLocal": "2023-07-01T00:40:00.0", "sleepEndTimestampLocal": + "2023-07-01T05:26:00.0"}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8c22bc4fbeb6df-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 18:14:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=K26isoQlhIUy1i4ANfOL1efqqIjmSH6tUk0Hf7JP59UL6VBoYZUZHyEHOzZ8pQcjWsDoUlbaFPGxcqQv5DsngZN6Ji8WsQY%2BhHNjn5t2KGN0gY%2FnV2O0gHI95EvJoadReFAtn4Zbuw%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_hydration_data.yaml b/tests/cassettes/test_hydration_data.yaml new file mode 100644 index 0000000..fe72eee --- /dev/null +++ b/tests/cassettes/test_hydration_data.yaml @@ -0,0 +1,246 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f967101d861154b-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:15:22 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=463w%2FuByRoJKGUmocUIzMvqYeScq0aei%2FT%2Bd3Ggsl8BMIlsKs%2BrGflSDcKjqo8BYotrFMwj6emCZ2IQ1MjkbQJMEy0l%2FRVf%2By7eQougtqIicbH9d%2Fds9HGH35hYJTPLg7cTEndSWFA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f9671031c331547-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:15:22 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=zqBSaLvwHc8CP3rS73t37hqtQPhwoJiQ0NDoQe7uMlDezK8fIqj%2BcDNd1ZkQqcC4SlQoImjwIkDRFK4oMCblXf4iKPgV%2FOQAV%2B8VNUSKzSyYQpQKsYKaAj6bjAt2Z1QYlwA%2Fhx6Rmw%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/usersummary-service/usersummary/hydration/daily/2023-07-01 + response: + body: + string: '{"userId": 2591602, "calendarDate": "2023-07-01", "valueInML": null, + "goalInML": 2800.0, "dailyAverageinML": null, "lastEntryTimestampLocal": null, + "sweatLossInML": null, "activityIntakeInML": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f967106dca5155f-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Sun, 20 Aug 2023 00:15:22 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=W0QFlPjJmMM%2FvZq47%2BpTK9Yu5mIQ0I88klxliwZmKHkGuibvBDOrovy8V8nfsoDWZroCHXBDJDD1lxuHapbfEtJetCyAPC1LzvaG3ETD3qjhCrvZjF7x%2F88teqWDnR%2F24les6bZuJA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_respiration_data.yaml b/tests/cassettes/test_respiration_data.yaml new file mode 100644 index 0000000..5a171c5 --- /dev/null +++ b/tests/cassettes/test_respiration_data.yaml @@ -0,0 +1,461 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f967264a894469e-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:16:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=Pplw7XeFrFBQGsxhQbxmv6CyYuk9Au5dsqX0wTdZOTBdwFHJIHPyHFODx%2BpAZvXGIlDawmircK1HaY6PEPvrrtS8dhI71CtDP%2BL6wnE7Zg3wfBaaMSALs4H%2BryDn4GMgQEA6q%2FxJmg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f9672657a45b6eb-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:16:18 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=5vujgX3CuoVNNop66LDmTlEIKzAwMQEOYVPexU9pSvaK9TDGrmKheF16geBIkb%2FMB0%2FrnXiSx%2F3%2BAeC1NTZi3v5AMfO727UmaRyrNxryz6nCDfIYsI4RdlD2cAO%2Fwnis%2FvgBT3%2FtEg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/wellness-service/wellness/daily/respiration/2023-07-01 + response: + body: + string: '{"userProfilePK": 2591602, "calendarDate": "2023-07-01", "startTimestampGMT": + "2023-07-01T06:00:00.0", "endTimestampGMT": "2023-07-02T06:00:00.0", "startTimestampLocal": + "2023-07-01T00:00:00.0", "endTimestampLocal": "2023-07-02T00:00:00.0", "sleepStartTimestampGMT": + "2023-07-01T06:40:00.0", "sleepEndTimestampGMT": "2023-07-01T11:26:00.0", + "sleepStartTimestampLocal": "2023-07-01T00:40:00.0", "sleepEndTimestampLocal": + "2023-07-01T05:26:00.0", "tomorrowSleepStartTimestampGMT": "2023-07-02T06:04:00.0", + "tomorrowSleepEndTimestampGMT": "2023-07-02T11:49:00.0", "tomorrowSleepStartTimestampLocal": + "2023-07-02T00:04:00.0", "tomorrowSleepEndTimestampLocal": "2023-07-02T05:49:00.0", + "lowestRespirationValue": 9.0, "highestRespirationValue": 21.0, "avgWakingRespirationValue": + 13.0, "avgSleepRespirationValue": 15.0, "avgTomorrowSleepRespirationValue": + 15.0, "respirationValueDescriptorsDTOList": [{"key": "timestamp", "index": + 0}, {"key": "respiration", "index": 1}], "respirationValuesArray": [[1688191320000, + 13.0], [1688191440000, 14.0], [1688191560000, 14.0], [1688191680000, 16.0], + [1688191800000, 17.0], [1688191920000, 15.0], [1688192040000, 15.0], [1688192160000, + 14.0], [1688192280000, 14.0], [1688192400000, 14.0], [1688192520000, 14.0], + [1688192640000, 13.0], [1688192760000, 13.0], [1688192880000, 13.0], [1688193000000, + 13.0], [1688193120000, 14.0], [1688193240000, 15.0], [1688193360000, 14.0], + [1688193480000, 17.0], [1688193600000, 17.0], [1688193720000, 15.0], [1688193840000, + 14.0], [1688193960000, 14.0], [1688194080000, 14.0], [1688194200000, 15.0], + [1688194320000, 14.0], [1688194440000, 13.0], [1688194560000, 16.0], [1688194680000, + 15.0], [1688194800000, 14.0], [1688194920000, 15.0], [1688195040000, 15.0], + [1688195160000, 15.0], [1688195280000, 15.0], [1688195400000, 15.0], [1688195520000, + 15.0], [1688195640000, 15.0], [1688195760000, 15.0], [1688195880000, 15.0], + [1688196000000, 15.0], [1688196120000, 15.0], [1688196240000, 15.0], [1688196360000, + 15.0], [1688196480000, 15.0], [1688196600000, 15.0], [1688196720000, 15.0], + [1688196840000, 15.0], [1688196960000, 15.0], [1688197080000, 15.0], [1688197200000, + 15.0], [1688197320000, 15.0], [1688197440000, 15.0], [1688197560000, 15.0], + [1688197680000, 14.0], [1688197800000, 14.0], [1688197920000, 13.0], [1688198040000, + 14.0], [1688198160000, 14.0], [1688198280000, 14.0], [1688198400000, 13.0], + [1688198520000, 15.0], [1688198640000, 14.0], [1688198760000, 15.0], [1688198880000, + 15.0], [1688199000000, 15.0], [1688199120000, 15.0], [1688199240000, 15.0], + [1688199360000, 15.0], [1688199480000, 15.0], [1688199600000, 16.0], [1688199720000, + 15.0], [1688199840000, 15.0], [1688199960000, 14.0], [1688200080000, 15.0], + [1688200200000, 14.0], [1688200320000, 15.0], [1688200440000, 15.0], [1688200560000, + 15.0], [1688200680000, 15.0], [1688200800000, 15.0], [1688200920000, 15.0], + [1688201040000, 15.0], [1688201160000, 15.0], [1688201280000, 15.0], [1688201400000, + 14.0], [1688201520000, 15.0], [1688201640000, 15.0], [1688201760000, 15.0], + [1688201880000, 15.0], [1688202000000, 14.0], [1688202120000, 14.0], [1688202240000, + 15.0], [1688202360000, 15.0], [1688202480000, 13.0], [1688202600000, 13.0], + [1688202720000, 14.0], [1688202840000, 14.0], [1688202960000, 14.0], [1688203080000, + 14.0], [1688203200000, 14.0], [1688203320000, 13.0], [1688203440000, 13.0], + [1688203560000, 13.0], [1688203680000, 13.0], [1688203800000, 15.0], [1688203920000, + 15.0], [1688204040000, 15.0], [1688204160000, 15.0], [1688204280000, 15.0], + [1688204400000, 14.0], [1688204520000, 14.0], [1688204640000, 14.0], [1688204760000, + 13.0], [1688204880000, 15.0], [1688205000000, 15.0], [1688205120000, 15.0], + [1688205240000, 15.0], [1688205360000, 15.0], [1688205480000, 15.0], [1688205600000, + 14.0], [1688205720000, 15.0], [1688205840000, 15.0], [1688205960000, 14.0], + [1688206080000, 14.0], [1688206200000, 15.0], [1688206320000, 15.0], [1688206440000, + 14.0], [1688206560000, 15.0], [1688206680000, 15.0], [1688206800000, 15.0], + [1688206920000, 15.0], [1688207040000, 14.0], [1688207160000, 14.0], [1688207280000, + 15.0], [1688207400000, 15.0], [1688207520000, 15.0], [1688207640000, 14.0], + [1688207760000, 14.0], [1688207880000, 15.0], [1688208000000, 15.0], [1688208120000, + 15.0], [1688208240000, 15.0], [1688208360000, 16.0], [1688208480000, 15.0], + [1688208600000, 14.0], [1688208720000, 14.0], [1688208840000, 15.0], [1688208960000, + 14.0], [1688209080000, 15.0], [1688209200000, 15.0], [1688209320000, 14.0], + [1688209440000, 12.0], [1688209560000, 12.0], [1688209680000, 14.0], [1688209800000, + 14.0], [1688209920000, 15.0], [1688210040000, 15.0], [1688210160000, 15.0], + [1688210280000, 15.0], [1688210400000, 14.0], [1688210520000, 14.0], [1688210640000, + 14.0], [1688210760000, 15.0], [1688210880000, 14.0], [1688211000000, -1.0], + [1688211120000, -1.0], [1688211240000, -1.0], [1688211360000, -1.0], [1688211480000, + 13.0], [1688211600000, 13.0], [1688211720000, 14.0], [1688211840000, 13.0], + [1688211960000, -1.0], [1688212080000, 14.0], [1688212200000, 14.0], [1688212320000, + 13.0], [1688212440000, 14.0], [1688212560000, 15.0], [1688212680000, 14.0], + [1688212800000, 16.0], [1688212920000, 14.0], [1688213040000, 14.0], [1688213160000, + 14.0], [1688213280000, 15.0], [1688213400000, 14.0], [1688213520000, 14.0], + [1688213640000, 16.0], [1688213760000, 16.0], [1688213880000, 15.0], [1688214000000, + 16.0], [1688214120000, 16.0], [1688214240000, 15.0], [1688214360000, 15.0], + [1688214480000, 15.0], [1688214600000, 13.0], [1688214720000, 12.0], [1688214840000, + 12.0], [1688214960000, 13.0], [1688215080000, 13.0], [1688215200000, 14.0], + [1688215320000, 14.0], [1688215440000, 13.0], [1688215560000, 13.0], [1688215680000, + 13.0], [1688215800000, 13.0], [1688215920000, 14.0], [1688216040000, 14.0], + [1688216160000, 14.0], [1688216280000, 13.0], [1688216400000, 13.0], [1688216520000, + 14.0], [1688216640000, 14.0], [1688216760000, 13.0], [1688216880000, 13.0], + [1688217000000, 12.0], [1688217120000, 12.0], [1688217240000, 13.0], [1688217360000, + 13.0], [1688217480000, 14.0], [1688217600000, 13.0], [1688217720000, 13.0], + [1688217840000, 13.0], [1688217960000, 10.0], [1688218080000, 11.0], [1688218200000, + 11.0], [1688218320000, 10.0], [1688218440000, -1.0], [1688218560000, 14.0], + [1688218680000, -1.0], [1688218800000, 14.0], [1688218920000, 14.0], [1688219040000, + 13.0], [1688219160000, -1.0], [1688219280000, 13.0], [1688219400000, 13.0], + [1688219520000, -1.0], [1688219640000, -1.0], [1688219760000, -1.0], [1688219880000, + 14.0], [1688220000000, 14.0], [1688220120000, 14.0], [1688220240000, 13.0], + [1688220360000, 13.0], [1688220480000, 13.0], [1688220600000, 12.0], [1688220720000, + -1.0], [1688220840000, -1.0], [1688220960000, -1.0], [1688221080000, -1.0], + [1688221200000, 13.0], [1688221320000, -1.0], [1688221440000, -1.0], [1688221560000, + -1.0], [1688221680000, 14.0], [1688221800000, -1.0], [1688221920000, -1.0], + [1688222040000, -1.0], [1688222160000, -1.0], [1688222280000, -1.0], [1688222400000, + -1.0], [1688222520000, 13.0], [1688222640000, 14.0], [1688222760000, 14.0], + [1688222880000, 14.0], [1688223000000, 14.0], [1688223120000, 15.0], [1688223240000, + -1.0], [1688223360000, -1.0], [1688223480000, -1.0], [1688223600000, 14.0], + [1688223720000, 14.0], [1688223840000, -1.0], [1688223960000, -1.0], [1688224080000, + 14.0], [1688224200000, -1.0], [1688224320000, 14.0], [1688224440000, 13.0], + [1688224560000, 13.0], [1688224680000, 14.0], [1688224800000, 14.0], [1688224920000, + 14.0], [1688225040000, 13.0], [1688225160000, 14.0], [1688225280000, 15.0], + [1688225400000, 14.0], [1688225520000, 13.0], [1688225640000, 14.0], [1688225760000, + 14.0], [1688225880000, -1.0], [1688226000000, -1.0], [1688226120000, 15.0], + [1688226240000, 14.0], [1688226360000, 13.0], [1688226480000, 14.0], [1688226600000, + -1.0], [1688226720000, -1.0], [1688226840000, -1.0], [1688226960000, 15.0], + [1688227080000, 15.0], [1688227200000, 13.0], [1688227320000, -1.0], [1688227440000, + -1.0], [1688227560000, -1.0], [1688227680000, -1.0], [1688227800000, -1.0], + [1688227920000, -1.0], [1688228040000, -1.0], [1688228160000, -1.0], [1688228280000, + 13.0], [1688228400000, 12.0], [1688228520000, 12.0], [1688228640000, 13.0], + [1688228760000, 13.0], [1688228880000, 14.0], [1688229000000, 13.0], [1688229120000, + 12.0], [1688229240000, -1.0], [1688229360000, 13.0], [1688229480000, 13.0], + [1688229600000, 13.0], [1688229720000, 13.0], [1688229840000, -1.0], [1688229960000, + 14.0], [1688230080000, -1.0], [1688230200000, 12.0], [1688230320000, -1.0], + [1688230440000, -1.0], [1688230560000, -1.0], [1688230680000, -1.0], [1688230800000, + -1.0], [1688230920000, 14.0], [1688231040000, 14.0], [1688231160000, 12.0], + [1688231280000, 13.0], [1688231400000, 14.0], [1688231520000, -1.0], [1688231640000, + 14.0], [1688231760000, 13.0], [1688231880000, 13.0], [1688232000000, 14.0], + [1688232120000, 14.0], [1688232240000, 14.0], [1688232360000, 14.0], [1688232480000, + 14.0], [1688232600000, 14.0], [1688232720000, 14.0], [1688232840000, 14.0], + [1688232960000, 13.0], [1688233080000, 14.0], [1688233200000, 13.0], [1688233320000, + 13.0], [1688233440000, 14.0], [1688233560000, 14.0], [1688233680000, 14.0], + [1688233800000, 14.0], [1688233920000, 14.0], [1688234040000, 13.0], [1688234160000, + 13.0], [1688234280000, 14.0], [1688234400000, 14.0], [1688234520000, 14.0], + [1688234640000, 13.0], [1688234760000, 14.0], [1688234880000, 14.0], [1688235000000, + 15.0], [1688235120000, 14.0], [1688235240000, 13.0], [1688235360000, 12.0], + [1688235480000, 12.0], [1688235600000, 15.0], [1688235720000, 15.0], [1688235840000, + 13.0], [1688235960000, 13.0], [1688236080000, 13.0], [1688236200000, 13.0], + [1688236320000, 13.0], [1688236440000, 13.0], [1688236560000, 14.0], [1688236680000, + 14.0], [1688236800000, 14.0], [1688236920000, 15.0], [1688237040000, 13.0], + [1688237160000, 13.0], [1688237280000, 14.0], [1688237400000, 13.0], [1688237520000, + 13.0], [1688237640000, 14.0], [1688237760000, 14.0], [1688237880000, 13.0], + [1688238000000, -1.0], [1688238120000, -1.0], [1688238240000, -1.0], [1688238360000, + -1.0], [1688238480000, -1.0], [1688238600000, -1.0], [1688238720000, -1.0], + [1688238840000, -1.0], [1688238960000, 16.0], [1688239080000, 16.0], [1688239200000, + -2.0], [1688239320000, -2.0], [1688239440000, -1.0], [1688239560000, -1.0], + [1688239680000, -1.0], [1688239800000, 14.0], [1688239920000, 14.0], [1688240040000, + -1.0], [1688240160000, -1.0], [1688240280000, -1.0], [1688240400000, -1.0], + [1688240520000, 13.0], [1688240640000, 13.0], [1688240760000, 13.0], [1688240880000, + -1.0], [1688241000000, -1.0], [1688241120000, -1.0], [1688241240000, -1.0], + [1688241360000, -1.0], [1688241480000, 14.0], [1688241600000, 15.0], [1688241720000, + 14.0], [1688241840000, 14.0], [1688241960000, 13.0], [1688242080000, 12.0], + [1688242200000, 13.0], [1688242320000, 13.0], [1688242440000, 13.0], [1688242560000, + 14.0], [1688242680000, 14.0], [1688242800000, 13.0], [1688242920000, 13.0], + [1688243040000, -1.0], [1688243160000, -1.0], [1688243280000, 13.0], [1688243400000, + 13.0], [1688243520000, 14.0], [1688243640000, 13.0], [1688243760000, 14.0], + [1688243880000, 12.0], [1688244000000, 12.0], [1688244120000, 13.0], [1688244240000, + 14.0], [1688244360000, 13.0], [1688244480000, -1.0], [1688244600000, 13.0], + [1688244720000, 15.0], [1688244840000, -1.0], [1688244960000, 14.0], [1688245080000, + 14.0], [1688245200000, 13.0], [1688245320000, 13.0], [1688245440000, -1.0], + [1688245560000, -1.0], [1688245680000, -1.0], [1688245800000, 13.0], [1688245920000, + 14.0], [1688246040000, 14.0], [1688246160000, 14.0], [1688246280000, 13.0], + [1688246400000, 13.0], [1688246520000, 13.0], [1688246640000, 13.0], [1688246760000, + 13.0], [1688246880000, 13.0], [1688247000000, 13.0], [1688247120000, 13.0], + [1688247240000, 14.0], [1688247360000, 13.0], [1688247480000, 12.0], [1688247600000, + 11.0], [1688247720000, 12.0], [1688247840000, -1.0], [1688247960000, -1.0], + [1688248080000, -1.0], [1688248200000, 14.0], [1688248320000, 13.0], [1688248440000, + 13.0], [1688248560000, -1.0], [1688248680000, -1.0], [1688248800000, 14.0], + [1688248920000, 13.0], [1688249040000, 12.0], [1688249160000, 12.0], [1688249280000, + -1.0], [1688249400000, -1.0], [1688249520000, 14.0], [1688249640000, 14.0], + [1688249760000, 13.0], [1688249880000, 13.0], [1688250000000, -1.0], [1688250120000, + -1.0], [1688250240000, -1.0], [1688250360000, -1.0], [1688250480000, 13.0], + [1688250600000, 13.0], [1688250720000, -1.0], [1688250840000, -1.0], [1688250960000, + -1.0], [1688251080000, 12.0], [1688251200000, 13.0], [1688251320000, -1.0], + [1688251440000, -1.0], [1688251560000, 14.0], [1688251680000, 13.0], [1688251800000, + 14.0], [1688251920000, 13.0], [1688252040000, 14.0], [1688252160000, -1.0], + [1688252280000, 14.0], [1688252400000, 13.0], [1688252520000, -1.0], [1688252640000, + 13.0], [1688252760000, 13.0], [1688252880000, 13.0], [1688253000000, -1.0], + [1688253120000, 13.0], [1688253240000, -1.0], [1688253360000, -1.0], [1688253480000, + -1.0], [1688253600000, -1.0], [1688253720000, 13.0], [1688253840000, 13.0], + [1688253960000, 13.0], [1688254080000, 13.0], [1688254200000, 14.0], [1688254320000, + -1.0], [1688254440000, -1.0], [1688254560000, 14.0], [1688254680000, -1.0], + [1688254800000, -1.0], [1688254920000, -1.0], [1688255040000, -1.0], [1688255160000, + 13.0], [1688255280000, -1.0], [1688255400000, 14.0], [1688255520000, -1.0], + [1688255640000, -1.0], [1688255760000, -1.0], [1688255880000, -1.0], [1688256000000, + 12.0], [1688256120000, 14.0], [1688256240000, 14.0], [1688256360000, 13.0], + [1688256480000, 12.0], [1688256600000, 15.0], [1688256720000, 20.0], [1688256840000, + 21.0], [1688256960000, 21.0], [1688257080000, 21.0], [1688257200000, 20.0], + [1688257320000, 18.0], [1688257440000, 16.0], [1688257560000, 14.0], [1688257680000, + 13.0], [1688257800000, 13.0], [1688257920000, 13.0], [1688258040000, 13.0], + [1688258160000, 13.0], [1688258280000, 12.0], [1688258400000, 12.0], [1688258520000, + 13.0], [1688258640000, 12.0], [1688258760000, 11.0], [1688258880000, 11.0], + [1688259000000, 13.0], [1688259120000, -1.0], [1688259240000, 14.0], [1688259360000, + 13.0], [1688259480000, 13.0], [1688259600000, 12.0], [1688259720000, 13.0], + [1688259840000, -1.0], [1688259960000, 13.0], [1688260080000, 14.0], [1688260200000, + 13.0], [1688260320000, 13.0], [1688260440000, 13.0], [1688260560000, 12.0], + [1688260680000, 13.0], [1688260800000, 13.0], [1688260920000, 13.0], [1688261040000, + 12.0], [1688261160000, 13.0], [1688261280000, 11.0], [1688261400000, 10.0], + [1688261520000, 11.0], [1688261640000, 13.0], [1688261760000, 14.0], [1688261880000, + 13.0], [1688262000000, 14.0], [1688262120000, -1.0], [1688262240000, -1.0], + [1688262360000, 13.0], [1688262480000, 14.0], [1688262600000, -1.0], [1688262720000, + 13.0], [1688262840000, 13.0], [1688262960000, -1.0], [1688263080000, -1.0], + [1688263200000, 12.0], [1688263320000, 14.0], [1688263440000, 14.0], [1688263560000, + 13.0], [1688263680000, 12.0], [1688263800000, 12.0], [1688263920000, 13.0], + [1688264040000, 13.0], [1688264160000, 13.0], [1688264280000, 13.0], [1688264400000, + 13.0], [1688264520000, 13.0], [1688264640000, 13.0], [1688264760000, 12.0], + [1688264880000, 12.0], [1688265000000, -1.0], [1688265120000, 14.0], [1688265240000, + 14.0], [1688265360000, 15.0], [1688265480000, 14.0], [1688265600000, 13.0], + [1688265720000, 13.0], [1688265840000, 13.0], [1688265960000, 13.0], [1688266080000, + 13.0], [1688266200000, 13.0], [1688266320000, 13.0], [1688266440000, 13.0], + [1688266560000, 13.0], [1688266680000, 13.0], [1688266800000, 13.0], [1688266920000, + 13.0], [1688267040000, 12.0], [1688267160000, 13.0], [1688267280000, 12.0], + [1688267400000, 11.0], [1688267520000, 10.0], [1688267640000, 10.0], [1688267760000, + 10.0], [1688267880000, 13.0], [1688268000000, 13.0], [1688268120000, 12.0], + [1688268240000, 12.0], [1688268360000, 14.0], [1688268480000, 14.0], [1688268600000, + 13.0], [1688268720000, 13.0], [1688268840000, 13.0], [1688268960000, 12.0], + [1688269080000, 12.0], [1688269200000, -1.0], [1688269320000, -1.0], [1688269440000, + -1.0], [1688269560000, -1.0], [1688269680000, -1.0], [1688269800000, 12.0], + [1688269920000, 13.0], [1688270040000, -1.0], [1688270160000, -1.0], [1688270280000, + 13.0], [1688270400000, 12.0], [1688270520000, 13.0], [1688270640000, 13.0], + [1688270760000, 13.0], [1688270880000, 14.0], [1688271000000, 13.0], [1688271120000, + 14.0], [1688271240000, 13.0], [1688271360000, 13.0], [1688271480000, 13.0], + [1688271600000, 12.0], [1688271720000, 13.0], [1688271840000, 14.0], [1688271960000, + 15.0], [1688272080000, 15.0], [1688272200000, 13.0], [1688272320000, 13.0], + [1688272440000, 13.0], [1688272560000, 13.0], [1688272680000, 14.0], [1688272800000, + 14.0], [1688272920000, 14.0], [1688273040000, 13.0], [1688273160000, 14.0], + [1688273280000, 13.0], [1688273400000, 12.0], [1688273520000, 13.0], [1688273640000, + 13.0], [1688273760000, 14.0], [1688273880000, 13.0], [1688274000000, 13.0], + [1688274120000, 14.0], [1688274240000, -1.0], [1688274360000, -1.0], [1688274480000, + 14.0], [1688274600000, -1.0], [1688274720000, -1.0], [1688274840000, -1.0], + [1688274960000, -1.0], [1688275080000, -1.0], [1688275200000, -1.0], [1688275320000, + -1.0], [1688275440000, -1.0], [1688275560000, 14.0], [1688275680000, 14.0], + [1688275800000, 14.0], [1688275920000, 15.0], [1688276040000, 14.0], [1688276160000, + 14.0], [1688276280000, -1.0], [1688276400000, 12.0], [1688276520000, -1.0], + [1688276640000, 11.0], [1688276760000, 10.0], [1688276880000, 11.0], [1688277000000, + -1.0], [1688277120000, 14.0], [1688277240000, -1.0], [1688277360000, 14.0], + [1688277480000, 16.0], [1688277600000, 18.0]]}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f9672679aa046e0-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:16:19 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=tIdu9j1vxLwcmOid2VTk%2FceMF0Fz09w5lrJ1ksDogFxdYKEka2JL6V3hM6y7gq0B2MnIbz9Y3X95pO4FYoFx49MKQZflS7VvXmKMtGQr1hUAZJ6rsxDehQfEtNONIQWKA8jSCYbhIg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_spo2_data.yaml b/tests/cassettes/test_spo2_data.yaml new file mode 100644 index 0000000..b5d4fa1 --- /dev/null +++ b/tests/cassettes/test_spo2_data.yaml @@ -0,0 +1,261 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f96736daf684654-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:17:01 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=8hCnedDFmiM8JESa95GBirj4lArL2UXpU0KwC2gVYU3RYcM%2B0nwXKnMDNu9pVkGr%2FeJxTSYq6P7DvEMgBMim08CRZWnwrRmrr5X3gk90UQ4KtsWoLpGum83XHfS4%2B9Umi%2B6ecrhYFA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f96736f6f5c46cb-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:17:01 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=yMear%2F3f3GXlzgu943Sz3ohKAGgRVM3hJhJSUve6tbFeDHwUZEc4rdCK1BpAgtN%2BOj%2BlVeGJ8kqjxxewjevaDx75HCQwa9kJlzP8NX%2FU1R5o6Zgg65ZA0iTN2Mr7SSKnKrTpLTUHxA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/wellness-service/wellness/daily/spo2/2023-07-01 + response: + body: + string: '{"userProfilePK": 2591602, "calendarDate": "2023-07-01", "startTimestampGMT": + "2023-07-01T06:00:00.0", "endTimestampGMT": "2023-07-02T06:00:00.0", "startTimestampLocal": + "2023-07-01T00:00:00.0", "endTimestampLocal": "2023-07-02T00:00:00.0", "sleepStartTimestampGMT": + "2023-07-01T06:40:00.0", "sleepEndTimestampGMT": "2023-07-01T11:26:00.0", + "sleepStartTimestampLocal": "2023-07-01T00:40:00.0", "sleepEndTimestampLocal": + "2023-07-01T05:26:00.0", "tomorrowSleepStartTimestampGMT": "2023-07-02T06:04:00.0", + "tomorrowSleepEndTimestampGMT": "2023-07-02T11:49:00.0", "tomorrowSleepStartTimestampLocal": + "2023-07-02T00:04:00.0", "tomorrowSleepEndTimestampLocal": "2023-07-02T05:49:00.0", + "averageSpO2": 92.0, "lowestSpO2": 85, "lastSevenDaysAvgSpO2": 92.14285714285714, + "latestSpO2": 86, "latestSpO2TimestampGMT": "2023-07-02T06:00:00.0", "latestSpO2TimestampLocal": + "2023-07-02T00:00:00.0", "avgSleepSpO2": 91.0, "avgTomorrowSleepSpO2": 91.0, + "spO2ValueDescriptorsDTOList": [{"spo2ValueDescriptorIndex": 0, "spo2ValueDescriptorKey": + "timestamp"}, {"spo2ValueDescriptorIndex": 1, "spo2ValueDescriptorKey": "spo2Reading"}, + {"spo2ValueDescriptorIndex": 2, "spo2ValueDescriptorKey": "singleReadingPlottable"}], + "spO2SingleValues": null, "continuousReadingDTOList": null, "spO2HourlyAverages": + [[1688191200000, 93], [1688194800000, 92], [1688198400000, 92], [1688202000000, + 91], [1688205600000, 92], [1688209200000, 92], [1688212800000, 95], [1688270400000, + 92], [1688274000000, 91]]}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f9673718c4e4612-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Sun, 20 Aug 2023 00:17:01 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=4V3RixJ95rW1%2FJhQSQVcbd9qjYC6BEbSquD1EWxS7UYGNW9u2BCAOZjGQzknvJvD29LUUQ6wLLO6yz3WS2tgCV8QpDbuJtqY%2Fww%2BLJHPZ5QJOTYprKzzieFQMixW%2FyTKOdp9hwJL4A%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_stats.yaml b/tests/cassettes/test_stats.yaml new file mode 100644 index 0000000..ffc753c --- /dev/null +++ b/tests/cassettes/test_stats.yaml @@ -0,0 +1,380 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.31.0 + method: GET + uri: https://thegarth.s3.amazonaws.com/oauth_consumer.json + response: + body: + string: '{"consumer_key": "SANITIZED", "consumer_secret": "SANITIZED"}' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '124' + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 03:34:01 GMT + ETag: + - '"20240b1013cb35419bb5b2cff1407a4e"' + Last-Modified: + - Thu, 03 Aug 2023 00:16:11 GMT + Server: + - AmazonS3 + x-amz-id-2: + - R7zVwQSGGFYnP/OaY5q6xyh3Gcgk3e9AhBYN1UyITG30CzhxyN27iyRBAY3DYZT+X57gwzt/duk= + x-amz-request-id: + - 36Y608PXR8QXGSCH + x-amz-server-side-encryption: + - AES256 + status: + code: 200 + message: OK +- request: + body: mfa_token=MFA-2032-l6G3RaeR91x4hBZoFvG6onbHvYrSMYAerVc0duF7pywYWLiub1-cas + headers: + Accept: + - !!binary | + Ki8q + Accept-Encoding: + - !!binary | + Z3ppcCwgZGVmbGF0ZQ== + Authorization: + - Bearer SANITIZED + Connection: + - !!binary | + a2VlcC1hbGl2ZQ== + Content-Length: + - '73' + Content-Type: + - !!binary | + YXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVk + User-Agent: + - !!binary | + Y29tLmdhcm1pbi5hbmRyb2lkLmFwcHMuY29ubmVjdG1vYmlsZQ== + method: POST + uri: https://connectapi.garmin.com/oauth-service/oauth/exchange/user/2.0 + response: + body: + string: '{"scope": "COMMUNITY_COURSE_READ GARMINPAY_WRITE GOLF_API_READ ATP_READ + GHS_SAMD GHS_UPLOAD INSIGHTS_READ COMMUNITY_COURSE_WRITE CONNECT_WRITE GCOFFER_WRITE + GARMINPAY_READ DT_CLIENT_ANALYTICS_WRITE GOLF_API_WRITE INSIGHTS_WRITE PRODUCT_SEARCH_READ + GCOFFER_READ CONNECT_READ ATP_WRITE", "jti": "SANITIZED", "access_token": + "SANITIZED", "token_type": "Bearer", "refresh_token": "SANITIZED", "expires_in": + 102053, "refresh_token_expires_in": 2591999}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f87193f28d7467d-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 03:34:01 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=nco%2B%2FkuMyKpMVxzT%2FJAxyVOW%2Fe8ZAHQ1AHfWNJrofA4xi4D1BSDjkBc9%2FPwlsJIMqgDvh7V6U%2FXvVQg7KfEn53ybKccuRCsgWjrBlXlYJonF5XEVndVSsRGi7zFYiG9kZWLFDj2Yng%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Set-Cookie: + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8719444b88b6ee-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 03:34:01 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=FHLUJ6gclJGE2hmU8io0iG5H7mnXiBH%2F0Kxif0JKQQ99ved77vTp3Uu6GnZi1VK5IJBsD7mvDmjuLGLGOtiiVp7ApzQsRlFSLOBPYA5dHnzWKutMrPFA72ot2TqnW6D%2F8alV6614Cg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f871946bb28464e-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 03:34:02 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=XuM%2FJWbKUjA%2FxEp%2BjovlwckL59G0zsCqCzBoXSbRZuDGgTSkCADoAs%2FrM6Ah7k8VkHXkbYt%2B5YWdZBfqgOFk2FjST9SJUXnkpF8bya7yZnwW10iaKxfpNmy0GXAeVt1wJeF4yfYYqA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/usersummary-service/usersummary/daily/mtamizi?calendarDate=2023-07-01 + response: + body: + string: '{"userProfileId": 2591602, "totalKilocalories": 2498.0, "activeKilocalories": + 370.0, "bmrKilocalories": 2128.0, "wellnessKilocalories": 2498.0, "burnedKilocalories": + null, "consumedKilocalories": null, "remainingKilocalories": 2498.0, "totalSteps": + 12413, "netCalorieGoal": null, "totalDistanceMeters": 10368, "wellnessDistanceMeters": + 10368, "wellnessActiveKilocalories": 370.0, "netRemainingKilocalories": 370.0, + "userDailySummaryId": 2591602, "calendarDate": "2023-07-01", "rule": {"typeId": + 2, "typeKey": "private"}, "uuid": "08064eebd5f64e299745fce9e3ae5c19", "dailyStepGoal": + 7950, "totalPushDistance": 0, "totalPushes": 0, "wellnessStartTimeGmt": "2023-07-01T06:00:00.0", + "wellnessStartTimeLocal": "2023-07-01T00:00:00.0", "wellnessEndTimeGmt": "2023-07-02T06:00:00.0", + "wellnessEndTimeLocal": "2023-07-02T00:00:00.0", "durationInMilliseconds": + 86400000, "wellnessDescription": null, "highlyActiveSeconds": 768, "activeSeconds": + 10219, "sedentarySeconds": 58253, "sleepingSeconds": 17160, "includesWellnessData": + true, "includesActivityData": false, "includesCalorieConsumedData": false, + "privacyProtected": false, "moderateIntensityMinutes": 0, "vigorousIntensityMinutes": + 0, "floorsAscendedInMeters": 90.802, "floorsDescendedInMeters": 88.567, "floorsAscended": + 29.79068, "floorsDescended": 29.05741, "intensityMinutesGoal": 150, "userFloorsAscendedGoal": + 35, "minHeartRate": 48, "maxHeartRate": 107, "restingHeartRate": 51, "lastSevenDaysAvgRestingHeartRate": + 49, "source": "GARMIN", "averageStressLevel": 35, "maxStressLevel": 86, "stressDuration": + 36120, "restStressDuration": 27780, "activityStressDuration": 17400, "uncategorizedStressDuration": + 5040, "totalStressDuration": 86340, "lowStressDuration": 21780, "mediumStressDuration": + 12660, "highStressDuration": 1680, "stressPercentage": 41.83, "restStressPercentage": + 32.18, "activityStressPercentage": 20.15, "uncategorizedStressPercentage": + 5.84, "lowStressPercentage": 25.23, "mediumStressPercentage": 14.66, "highStressPercentage": + 1.95, "stressQualifier": "STRESSFUL", "measurableAwakeDuration": 64260, "measurableAsleepDuration": + 17040, "lastSyncTimestampGMT": null, "minAvgHeartRate": 49, "maxAvgHeartRate": + 106, "bodyBatteryChargedValue": 43, "bodyBatteryDrainedValue": 43, "bodyBatteryHighestValue": + 48, "bodyBatteryLowestValue": 5, "bodyBatteryMostRecentValue": 5, "bodyBatteryVersion": + 2.0, "abnormalHeartRateAlertsCount": null, "averageSpo2": 92.0, "lowestSpo2": + 85, "latestSpo2": 86, "latestSpo2ReadingTimeGmt": "2023-07-02T06:00:00.0", + "latestSpo2ReadingTimeLocal": "2023-07-02T00:00:00.0", "averageMonitoringEnvironmentAltitude": + 2254.0, "restingCaloriesFromActivity": null, "avgWakingRespirationValue": + 13.0, "highestRespirationValue": 21.0, "lowestRespirationValue": 9.0, "latestRespirationValue": + 18.0, "latestRespirationTimeGMT": "2023-07-02T06:00:00.0"}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f87194bfc474630-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 03:34:02 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=tuYDE5sNjkqgtYm%2Fxb9mKn7QlL0LOZE0mFIH09bXZa9UMyHN3G62ptc5H4P8asYIyOpeeA0veLeCpMXfY%2Bc96FrojM6fTw16LnIf%2BrW%2BWCrnbVHkD1%2BMePyd%2FhsJWeXjCMScUqkntg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_stats_and_body.yaml b/tests/cassettes/test_stats_and_body.yaml new file mode 100644 index 0000000..58fa0b4 --- /dev/null +++ b/tests/cassettes/test_stats_and_body.yaml @@ -0,0 +1,341 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/socialProfile + response: + body: + string: '{"id": 3154645, "profileId": 2591602, "garminGUID": "0690cc1d-d23d-4412-b027-80fd4ed1c0f6", + "displayName": "mtamizi", "fullName": "Matin Tamizi", "userName": "mtamizi", + "profileImageUuid": "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f", "profileImageUrlLarge": + "https://s3.amazonaws.com/garmin-connect-prod/profile_images/73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png", + "profileImageUrlMedium": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png", + "profileImageUrlSmall": "https://s3.amazonaws.com/garmin-connect-prod/profile_images/6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png", + "location": "Ciudad de M\u00e9xico, CDMX", "facebookUrl": null, "twitterUrl": + null, "personalWebsite": null, "motivation": null, "bio": null, "primaryActivity": + null, "favoriteActivityTypes": [], "runningTrainingSpeed": 0.0, "cyclingTrainingSpeed": + 0.0, "favoriteCyclingActivityTypes": [], "cyclingClassification": null, "cyclingMaxAvgPower": + 0.0, "swimmingTrainingSpeed": 0.0, "profileVisibility": "private", "activityStartVisibility": + "private", "activityMapVisibility": "public", "courseVisibility": "public", + "activityHeartRateVisibility": "public", "activityPowerVisibility": "public", + "badgeVisibility": "private", "showAge": false, "showWeight": false, "showHeight": + false, "showWeightClass": false, "showAgeRange": false, "showGender": false, + "showActivityClass": false, "showVO2Max": false, "showPersonalRecords": false, + "showLast12Months": false, "showLifetimeTotals": false, "showUpcomingEvents": + false, "showRecentFavorites": false, "showRecentDevice": false, "showRecentGear": + false, "showBadges": true, "otherActivity": null, "otherPrimaryActivity": + null, "otherMotivation": null, "userRoles": ["SCOPE_ATP_READ", "SCOPE_ATP_WRITE", + "SCOPE_COMMUNITY_COURSE_READ", "SCOPE_COMMUNITY_COURSE_WRITE", "SCOPE_CONNECT_READ", + "SCOPE_CONNECT_WRITE", "SCOPE_DT_CLIENT_ANALYTICS_WRITE", "SCOPE_GARMINPAY_READ", + "SCOPE_GARMINPAY_WRITE", "SCOPE_GCOFFER_READ", "SCOPE_GCOFFER_WRITE", "SCOPE_GHS_SAMD", + "SCOPE_GHS_UPLOAD", "SCOPE_GOLF_API_READ", "SCOPE_GOLF_API_WRITE", "SCOPE_INSIGHTS_READ", + "SCOPE_INSIGHTS_WRITE", "SCOPE_PRODUCT_SEARCH_READ", "ROLE_CONNECTUSER", "ROLE_FITNESS_USER", + "ROLE_WELLNESS_USER", "ROLE_OUTDOOR_USER", "ROLE_CONNECT_2_USER", "ROLE_TACX_APP_USER"], + "nameApproved": true, "userProfileFullName": "Matin Tamizi", "makeGolfScorecardsPrivate": + true, "allowGolfLiveScoring": false, "allowGolfScoringByConnections": true, + "userLevel": 3, "userPoint": 117, "levelUpdateDate": "2020-12-12T15:20:38.0", + "levelIsViewed": false, "levelPointThreshold": 140, "userPointOffset": 0, + "userPro": false}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a56095b71b6e7-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 12:59:48 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=xnumb7924cZnXVSAdsgVPkUyq4aBAZa%2BzoO3Fg%2FyKNqahpZsaKnF2Nj2q4rjgRfCbcjVyIhh1QOGJ4bF54hFZLJ%2FXDvVNkSCixzHaiB0NYlCUosW%2FnpqZ9qzSlK04O11fOMhncqjLA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a560a29521556-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 12:59:48 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=9rAywogINvfA%2FLcuCArFPR%2Fb03HHA%2BgJetJMJ13SBPSBezpQ7Ix%2Bv1hHyY4vIzAOszB0BxbPnhqPZwTBOamu6uYEc6ktsgDx6%2FZw21w6a6Iw64vSxI106onMPYR19Hdu2XjTQdwdBQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/usersummary-service/usersummary/daily/mtamizi?calendarDate=2023-07-01 + response: + body: + string: '{"userProfileId": 2591602, "totalKilocalories": 2498.0, "activeKilocalories": + 370.0, "bmrKilocalories": 2128.0, "wellnessKilocalories": 2498.0, "burnedKilocalories": + null, "consumedKilocalories": null, "remainingKilocalories": 2498.0, "totalSteps": + 12413, "netCalorieGoal": null, "totalDistanceMeters": 10368, "wellnessDistanceMeters": + 10368, "wellnessActiveKilocalories": 370.0, "netRemainingKilocalories": 370.0, + "userDailySummaryId": 2591602, "calendarDate": "2023-07-01", "rule": {"typeId": + 2, "typeKey": "private"}, "uuid": "08064eebd5f64e299745fce9e3ae5c19", "dailyStepGoal": + 7950, "totalPushDistance": 0, "totalPushes": 0, "wellnessStartTimeGmt": "2023-07-01T06:00:00.0", + "wellnessStartTimeLocal": "2023-07-01T00:00:00.0", "wellnessEndTimeGmt": "2023-07-02T06:00:00.0", + "wellnessEndTimeLocal": "2023-07-02T00:00:00.0", "durationInMilliseconds": + 86400000, "wellnessDescription": null, "highlyActiveSeconds": 768, "activeSeconds": + 10219, "sedentarySeconds": 58253, "sleepingSeconds": 17160, "includesWellnessData": + true, "includesActivityData": false, "includesCalorieConsumedData": false, + "privacyProtected": false, "moderateIntensityMinutes": 0, "vigorousIntensityMinutes": + 0, "floorsAscendedInMeters": 90.802, "floorsDescendedInMeters": 88.567, "floorsAscended": + 29.79068, "floorsDescended": 29.05741, "intensityMinutesGoal": 150, "userFloorsAscendedGoal": + 35, "minHeartRate": 48, "maxHeartRate": 107, "restingHeartRate": 51, "lastSevenDaysAvgRestingHeartRate": + 49, "source": "GARMIN", "averageStressLevel": 35, "maxStressLevel": 86, "stressDuration": + 36120, "restStressDuration": 27780, "activityStressDuration": 17400, "uncategorizedStressDuration": + 5040, "totalStressDuration": 86340, "lowStressDuration": 21780, "mediumStressDuration": + 12660, "highStressDuration": 1680, "stressPercentage": 41.83, "restStressPercentage": + 32.18, "activityStressPercentage": 20.15, "uncategorizedStressPercentage": + 5.84, "lowStressPercentage": 25.23, "mediumStressPercentage": 14.66, "highStressPercentage": + 1.95, "stressQualifier": "STRESSFUL", "measurableAwakeDuration": 64260, "measurableAsleepDuration": + 17040, "lastSyncTimestampGMT": null, "minAvgHeartRate": 49, "maxAvgHeartRate": + 106, "bodyBatteryChargedValue": 43, "bodyBatteryDrainedValue": 43, "bodyBatteryHighestValue": + 48, "bodyBatteryLowestValue": 5, "bodyBatteryMostRecentValue": 5, "bodyBatteryVersion": + 2.0, "abnormalHeartRateAlertsCount": null, "averageSpo2": 92.0, "lowestSpo2": + 85, "latestSpo2": 86, "latestSpo2ReadingTimeGmt": "2023-07-02T06:00:00.0", + "latestSpo2ReadingTimeLocal": "2023-07-02T00:00:00.0", "averageMonitoringEnvironmentAltitude": + 2254.0, "restingCaloriesFromActivity": null, "avgWakingRespirationValue": + 13.0, "highestRespirationValue": 21.0, "lowestRespirationValue": 9.0, "latestRespirationValue": + 18.0, "latestRespirationTimeGMT": "2023-07-02T06:00:00.0"}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a560b1e471557-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 12:59:48 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=Pop5dpRgSkel9wBP3m0EVt%2Br9RHJcHUMoAkg9SteHwaj%2BVVCsDzaCRLCtaroyZ3%2F4Ckqr7sWT91zwPzbg64rN9M%2FYPag%2Bb630vreTUeGLer7TjX38HjbOfHVFstRah9k1QoEIJ7vbg%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/weight-service/weight/dateRange?startDate=2023-07-01&endDate=2023-07-01 + response: + body: + string: '{"startDate": "2023-07-01", "endDate": "2023-07-01", "dateWeightList": + [], "totalAverage": {"from": 1688169600000, "until": 1688255999999, "weight": + null, "bmi": null, "bodyFat": null, "bodyWater": null, "boneMass": null, "muscleMass": + null, "physiqueRating": null, "visceralFat": null, "metabolicAge": null}}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f8a560c6b6fb6e5-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 12:59:48 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=ic7LyCpt86r5D2o6Dcd5K4S3vghREmCTp40Kmrbtjj7bQCyf2PBh%2BOuSc9xQILHTQ2edEFtVHqfX7U7V4NVbCti0BxAUCIc9JI6MhFpzRWn9y%2FUvnuPREox17qs7HQ%2BAIoIiz1nVDA%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_steps_data.yaml b/tests/cassettes/test_steps_data.yaml new file mode 100644 index 0000000..87f12a3 --- /dev/null +++ b/tests/cassettes/test_steps_data.yaml @@ -0,0 +1,336 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f873ddaf815b6ed-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 03:59:00 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=3dTHCTMSRwi%2F0Ahvm1maSWvDJOjAMveznEpyN%2F5DWLcjzHP0hXHS8tVKpiaAIW42ziwHj7E52yQC4Jt7KwGiUFCdbb2gqizHjlMVST8OzUSSwWhmJf3ljzr7FkpgoOMoboppJ7mBYQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/wellness-service/wellness/dailySummaryChart/mtamizi?date=2023-07-01 + response: + body: + string: '[{"startGMT": "2023-07-01T06:00:00.0", "endGMT": "2023-07-01T06:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T06:15:00.0", "endGMT": "2023-07-01T06:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T06:30:00.0", "endGMT": "2023-07-01T06:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T06:45:00.0", "endGMT": "2023-07-01T07:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T07:00:00.0", "endGMT": "2023-07-01T07:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T07:15:00.0", "endGMT": "2023-07-01T07:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T07:30:00.0", "endGMT": "2023-07-01T07:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T07:45:00.0", "endGMT": "2023-07-01T08:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T08:00:00.0", "endGMT": "2023-07-01T08:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T08:15:00.0", "endGMT": "2023-07-01T08:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T08:30:00.0", "endGMT": "2023-07-01T08:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T08:45:00.0", "endGMT": "2023-07-01T09:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T09:00:00.0", "endGMT": "2023-07-01T09:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T09:15:00.0", "endGMT": "2023-07-01T09:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T09:30:00.0", "endGMT": "2023-07-01T09:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T09:45:00.0", "endGMT": "2023-07-01T10:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T10:00:00.0", "endGMT": "2023-07-01T10:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T10:15:00.0", "endGMT": "2023-07-01T10:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T10:30:00.0", "endGMT": "2023-07-01T10:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T10:45:00.0", "endGMT": "2023-07-01T11:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T11:00:00.0", "endGMT": "2023-07-01T11:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T11:15:00.0", "endGMT": "2023-07-01T11:30:00.0", + "steps": 56, "pushes": 0, "primaryActivityLevel": "sleeping", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T11:30:00.0", "endGMT": "2023-07-01T11:45:00.0", + "steps": 406, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T11:45:00.0", "endGMT": "2023-07-01T12:00:00.0", + "steps": 27, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T12:00:00.0", "endGMT": "2023-07-01T12:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T12:15:00.0", "endGMT": "2023-07-01T12:30:00.0", + "steps": 39, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T12:30:00.0", "endGMT": "2023-07-01T12:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "highlyActive", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T12:45:00.0", "endGMT": "2023-07-01T13:00:00.0", + "steps": 35, "pushes": 0, "primaryActivityLevel": "highlyActive", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T13:00:00.0", "endGMT": "2023-07-01T13:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T13:15:00.0", "endGMT": "2023-07-01T13:30:00.0", + "steps": 13, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T13:30:00.0", "endGMT": "2023-07-01T13:45:00.0", + "steps": 457, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T13:45:00.0", "endGMT": "2023-07-01T14:00:00.0", + "steps": 370, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T14:00:00.0", "endGMT": "2023-07-01T14:15:00.0", + "steps": 135, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T14:15:00.0", "endGMT": "2023-07-01T14:30:00.0", + "steps": 1006, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T14:30:00.0", "endGMT": "2023-07-01T14:45:00.0", + "steps": 901, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T14:45:00.0", "endGMT": "2023-07-01T15:00:00.0", + "steps": 79, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T15:00:00.0", "endGMT": "2023-07-01T15:15:00.0", + "steps": 83, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T15:15:00.0", "endGMT": "2023-07-01T15:30:00.0", + "steps": 21, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T15:30:00.0", "endGMT": "2023-07-01T15:45:00.0", + "steps": 189, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T15:45:00.0", "endGMT": "2023-07-01T16:00:00.0", + "steps": 941, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T16:00:00.0", "endGMT": "2023-07-01T16:15:00.0", + "steps": 842, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T16:15:00.0", "endGMT": "2023-07-01T16:30:00.0", + "steps": 38, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T16:30:00.0", "endGMT": "2023-07-01T16:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T16:45:00.0", "endGMT": "2023-07-01T17:00:00.0", + "steps": 513, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T17:00:00.0", "endGMT": "2023-07-01T17:15:00.0", + "steps": 106, "pushes": 0, "primaryActivityLevel": "highlyActive", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T17:15:00.0", "endGMT": "2023-07-01T17:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T17:30:00.0", "endGMT": "2023-07-01T17:45:00.0", + "steps": 19, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T17:45:00.0", "endGMT": "2023-07-01T18:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T18:00:00.0", "endGMT": "2023-07-01T18:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T18:15:00.0", "endGMT": "2023-07-01T18:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T18:30:00.0", "endGMT": "2023-07-01T18:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T18:45:00.0", "endGMT": "2023-07-01T19:00:00.0", + "steps": 53, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T19:00:00.0", "endGMT": "2023-07-01T19:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T19:15:00.0", "endGMT": "2023-07-01T19:30:00.0", + "steps": 158, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T19:30:00.0", "endGMT": "2023-07-01T19:45:00.0", + "steps": 495, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T19:45:00.0", "endGMT": "2023-07-01T20:00:00.0", + "steps": 348, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T20:00:00.0", "endGMT": "2023-07-01T20:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T20:15:00.0", "endGMT": "2023-07-01T20:30:00.0", + "steps": 214, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T20:30:00.0", "endGMT": "2023-07-01T20:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T20:45:00.0", "endGMT": "2023-07-01T21:00:00.0", + "steps": 173, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T21:00:00.0", "endGMT": "2023-07-01T21:15:00.0", + "steps": 199, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T21:15:00.0", "endGMT": "2023-07-01T21:30:00.0", + "steps": 38, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T21:30:00.0", "endGMT": "2023-07-01T21:45:00.0", + "steps": 348, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T21:45:00.0", "endGMT": "2023-07-01T22:00:00.0", + "steps": 544, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T22:00:00.0", "endGMT": "2023-07-01T22:15:00.0", + "steps": 217, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T22:15:00.0", "endGMT": "2023-07-01T22:30:00.0", + "steps": 133, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T22:30:00.0", "endGMT": "2023-07-01T22:45:00.0", + "steps": 63, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T22:45:00.0", "endGMT": "2023-07-01T23:00:00.0", + "steps": 39, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T23:00:00.0", "endGMT": "2023-07-01T23:15:00.0", + "steps": 144, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-01T23:15:00.0", "endGMT": "2023-07-01T23:30:00.0", + "steps": 42, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T23:30:00.0", "endGMT": "2023-07-01T23:45:00.0", + "steps": 320, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + true}, {"startGMT": "2023-07-01T23:45:00.0", "endGMT": "2023-07-02T00:00:00.0", + "steps": 540, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T00:00:00.0", "endGMT": "2023-07-02T00:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T00:15:00.0", "endGMT": "2023-07-02T00:30:00.0", + "steps": 84, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T00:30:00.0", "endGMT": "2023-07-02T00:45:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T00:45:00.0", "endGMT": "2023-07-02T01:00:00.0", + "steps": 140, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T01:00:00.0", "endGMT": "2023-07-02T01:15:00.0", + "steps": 63, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T01:15:00.0", "endGMT": "2023-07-02T01:30:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T01:30:00.0", "endGMT": "2023-07-02T01:45:00.0", + "steps": 164, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T01:45:00.0", "endGMT": "2023-07-02T02:00:00.0", + "steps": 318, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T02:00:00.0", "endGMT": "2023-07-02T02:15:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T02:15:00.0", "endGMT": "2023-07-02T02:30:00.0", + "steps": 23, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T02:30:00.0", "endGMT": "2023-07-02T02:45:00.0", + "steps": 13, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T02:45:00.0", "endGMT": "2023-07-02T03:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T03:00:00.0", "endGMT": "2023-07-02T03:15:00.0", + "steps": 13, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T03:15:00.0", "endGMT": "2023-07-02T03:30:00.0", + "steps": 9, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T03:30:00.0", "endGMT": "2023-07-02T03:45:00.0", + "steps": 101, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T03:45:00.0", "endGMT": "2023-07-02T04:00:00.0", + "steps": 279, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T04:00:00.0", "endGMT": "2023-07-02T04:15:00.0", + "steps": 10, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T04:15:00.0", "endGMT": "2023-07-02T04:30:00.0", + "steps": 12, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T04:30:00.0", "endGMT": "2023-07-02T04:45:00.0", + "steps": 11, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T04:45:00.0", "endGMT": "2023-07-02T05:00:00.0", + "steps": 0, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}, {"startGMT": "2023-07-02T05:00:00.0", "endGMT": "2023-07-02T05:15:00.0", + "steps": 151, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T05:15:00.0", "endGMT": "2023-07-02T05:30:00.0", + "steps": 294, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T05:30:00.0", "endGMT": "2023-07-02T05:45:00.0", + "steps": 365, "pushes": 0, "primaryActivityLevel": "active", "activityLevelConstant": + false}, {"startGMT": "2023-07-02T05:45:00.0", "endGMT": "2023-07-02T06:00:00.0", + "steps": 19, "pushes": 0, "primaryActivityLevel": "sedentary", "activityLevelConstant": + true}]' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f873ddd1a594791-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 03:59:00 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=tJacsT8vopyIAffN684LcOMbK15rMrBOqEpskYmxq4YlGwiZbrizv9WNX6lEBv89nLZ0SdMqmuDY8QGV6NKFFb2PWZkFEjQLcywqorvWGMblFTGOwq0njWceIXlL7xZkc70Bx%2BHpHQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_user_summary.yaml b/tests/cassettes/test_user_summary.yaml new file mode 100644 index 0000000..dae73dd --- /dev/null +++ b/tests/cassettes/test_user_summary.yaml @@ -0,0 +1,182 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/userprofile-service/userprofile/user-settings + response: + body: + string: '{"id": 2591602, "userData": {"gender": "MALE", "weight": 79800.0, "height": + 182.0, "timeFormat": "time_twenty_four_hr", "birthDate": "1984-10-17", "measurementSystem": + "metric", "activityLevel": null, "handedness": "RIGHT", "powerFormat": {"formatId": + 30, "formatKey": "watt", "minFraction": 0, "maxFraction": 0, "groupingUsed": + true, "displayFormat": null}, "heartRateFormat": {"formatId": 21, "formatKey": + "bpm", "minFraction": 0, "maxFraction": 0, "groupingUsed": false, "displayFormat": + null}, "firstDayOfWeek": {"dayId": 2, "dayName": "sunday", "sortOrder": 2, + "isPossibleFirstDay": true}, "vo2MaxRunning": 46.0, "vo2MaxCycling": null, + "lactateThresholdSpeed": 0.34722125000000004, "lactateThresholdHeartRate": + null, "diveNumber": null, "intensityMinutesCalcMethod": "AUTO", "moderateIntensityMinutesHrZone": + 3, "vigorousIntensityMinutesHrZone": 4, "hydrationMeasurementUnit": "milliliter", + "hydrationContainers": [], "hydrationAutoGoalEnabled": true, "firstbeatMaxStressScore": + null, "firstbeatCyclingLtTimestamp": null, "firstbeatRunningLtTimestamp": + 1044719868, "thresholdHeartRateAutoDetected": true, "ftpAutoDetected": null, + "trainingStatusPausedDate": null, "weatherLocation": {"useFixedLocation": + false, "latitude": null, "longitude": null, "locationName": null, "isoCountryCode": + null, "postalCode": null}, "golfDistanceUnit": "statute_us", "golfElevationUnit": + null, "golfSpeedUnit": null, "externalBottomTime": null}, "userSleep": {"sleepTime": + 80400, "defaultSleepTime": false, "wakeTime": 24000, "defaultWakeTime": false}, + "connectDate": null, "sourceType": null}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f873cc1594eb6ed-QRO + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 18 Aug 2023 03:58:15 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=aEek6tpphYzvySDDJURR7L7T%2FYzHg1kFiECinHHd49fQL3L9uzMItVct2bhBMrlxghE246LjQ8ktcvbwRsQthnLRkZIyGzVYOlltlOQYYJnF8s7LTNixQeIQYIvXF1E122T5qlNMlQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - _cfuvid=SANITIZED; path=SANITIZED; domain=SANITIZED; HttpOnly; Secure; SameSite=SANITIZED + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer SANITIZED + Connection: + - keep-alive + Cookie: + - _cfuvid=SANITIZED; ADRUM_BT1=SANITIZED; ADRUM_BTa=SANITIZED; SameSite=SANITIZED + User-Agent: + - Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Mobile/15E148 + method: GET + uri: https://connectapi.garmin.com/usersummary-service/usersummary/daily/mtamizi?calendarDate=2023-07-01 + response: + body: + string: '{"userProfileId": 2591602, "totalKilocalories": 2498.0, "activeKilocalories": + 370.0, "bmrKilocalories": 2128.0, "wellnessKilocalories": 2498.0, "burnedKilocalories": + null, "consumedKilocalories": null, "remainingKilocalories": 2498.0, "totalSteps": + 12413, "netCalorieGoal": null, "totalDistanceMeters": 10368, "wellnessDistanceMeters": + 10368, "wellnessActiveKilocalories": 370.0, "netRemainingKilocalories": 370.0, + "userDailySummaryId": 2591602, "calendarDate": "2023-07-01", "rule": {"typeId": + 2, "typeKey": "private"}, "uuid": "08064eebd5f64e299745fce9e3ae5c19", "dailyStepGoal": + 7950, "totalPushDistance": 0, "totalPushes": 0, "wellnessStartTimeGmt": "2023-07-01T06:00:00.0", + "wellnessStartTimeLocal": "2023-07-01T00:00:00.0", "wellnessEndTimeGmt": "2023-07-02T06:00:00.0", + "wellnessEndTimeLocal": "2023-07-02T00:00:00.0", "durationInMilliseconds": + 86400000, "wellnessDescription": null, "highlyActiveSeconds": 768, "activeSeconds": + 10219, "sedentarySeconds": 58253, "sleepingSeconds": 17160, "includesWellnessData": + true, "includesActivityData": false, "includesCalorieConsumedData": false, + "privacyProtected": false, "moderateIntensityMinutes": 0, "vigorousIntensityMinutes": + 0, "floorsAscendedInMeters": 90.802, "floorsDescendedInMeters": 88.567, "floorsAscended": + 29.79068, "floorsDescended": 29.05741, "intensityMinutesGoal": 150, "userFloorsAscendedGoal": + 35, "minHeartRate": 48, "maxHeartRate": 107, "restingHeartRate": 51, "lastSevenDaysAvgRestingHeartRate": + 49, "source": "GARMIN", "averageStressLevel": 35, "maxStressLevel": 86, "stressDuration": + 36120, "restStressDuration": 27780, "activityStressDuration": 17400, "uncategorizedStressDuration": + 5040, "totalStressDuration": 86340, "lowStressDuration": 21780, "mediumStressDuration": + 12660, "highStressDuration": 1680, "stressPercentage": 41.83, "restStressPercentage": + 32.18, "activityStressPercentage": 20.15, "uncategorizedStressPercentage": + 5.84, "lowStressPercentage": 25.23, "mediumStressPercentage": 14.66, "highStressPercentage": + 1.95, "stressQualifier": "STRESSFUL", "measurableAwakeDuration": 64260, "measurableAsleepDuration": + 17040, "lastSyncTimestampGMT": null, "minAvgHeartRate": 49, "maxAvgHeartRate": + 106, "bodyBatteryChargedValue": 43, "bodyBatteryDrainedValue": 43, "bodyBatteryHighestValue": + 48, "bodyBatteryLowestValue": 5, "bodyBatteryMostRecentValue": 5, "bodyBatteryVersion": + 2.0, "abnormalHeartRateAlertsCount": null, "averageSpo2": 92.0, "lowestSpo2": + 85, "latestSpo2": 86, "latestSpo2ReadingTimeGmt": "2023-07-02T06:00:00.0", + "latestSpo2ReadingTimeLocal": "2023-07-02T00:00:00.0", "averageMonitoringEnvironmentAltitude": + 2254.0, "restingCaloriesFromActivity": null, "avgWakingRespirationValue": + 13.0, "highestRespirationValue": 21.0, "lowestRespirationValue": 9.0, "latestRespirationValue": + 18.0, "latestRespirationTimeGMT": "2023-07-02T06:00:00.0"}' + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 7f873cc6a8b54659-DFW + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 18 Aug 2023 03:58:16 GMT + NEL: + - '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}' + Report-To: + - '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=l9QNfRD2GFrbmbYPa0jUrwjJxNySHcV%2Fy4Hj2ihXGsjhhe4M6PaV2Oa7HbD2p4ide12TeIY0HlsR52xOurplH8bOicHR8kwOIqH2FsW4Wu7VOMC5DgBtFLnDIEmlDwSByNTflvwIuQ%3D%3D"}],"group":"cf-nel","max_age":604800}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - no-cache, no-store, private + pragma: + - no-cache + set-cookie: + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTa=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - SameSite=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BT1=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + - ADRUM_BTs=SANITIZED; Max-Age=SANITIZED; Expires=SANITIZED; Path=SANITIZED; + Secure + status: + code: 200 + message: OK +version: 1 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..2bcea49 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,75 @@ +import json +import os +import re + +import pytest + + +@pytest.fixture +def vcr(vcr): + if "GARTH_HOME" not in os.environ: + vcr.record_mode = "none" + return vcr + + +def sanitize_cookie(cookie_value) -> str: + return re.sub(r"=[^;]*", "=SANITIZED", cookie_value) + + +def sanitize_request(request): + if request.body: + body = request.body.decode("utf8") + for key in ["username", "password", "refresh_token"]: + body = re.sub(key + r"=[^&]*", f"{key}=SANITIZED", body) + request.body = body.encode("utf8") + + if "Cookie" in request.headers: + cookies = request.headers["Cookie"].split("; ") + sanitized_cookies = [sanitize_cookie(cookie) for cookie in cookies] + request.headers["Cookie"] = "; ".join(sanitized_cookies) + return request + + +def sanitize_response(response): + for key in ["set-cookie", "Set-Cookie"]: + if key in response["headers"]: + cookies = response["headers"][key] + sanitized_cookies = [sanitize_cookie(cookie) for cookie in cookies] + response["headers"][key] = sanitized_cookies + + body = response["body"]["string"].decode("utf8") + patterns = [ + "oauth_token=[^&]*", + "oauth_token_secret=[^&]*", + "mfa_token=[^&]*", + ] + for pattern in patterns: + body = re.sub(pattern, pattern.split("=")[0] + "=SANITIZED", body) + try: + body_json = json.loads(body) + except json.JSONDecodeError: + pass + else: + for field in [ + "access_token", + "refresh_token", + "jti", + "consumer_key", + "consumer_secret", + ]: + if field in body_json: + body_json[field] = "SANITIZED" + + body = json.dumps(body_json) + response["body"]["string"] = body.encode("utf8") + + return response + + +@pytest.fixture(scope="session") +def vcr_config(): + return { + "filter_headers": [("Authorization", "Bearer SANITIZED")], + "before_record_request": sanitize_request, + "before_record_response": sanitize_response, + } diff --git a/tests/test_garmin.py b/tests/test_garmin.py new file mode 100644 index 0000000..f5a2bd1 --- /dev/null +++ b/tests/test_garmin.py @@ -0,0 +1,122 @@ +import pytest + +import garminconnect + + +DATE = "2023-07-01" + + +@pytest.fixture(scope="session") +def garmin(): + return garminconnect.Garmin("email", "password") + + +@pytest.mark.vcr +def test_stats(garmin): + garmin.login() + stats = garmin.get_stats(DATE) + assert "totalKilocalories" in stats + assert "activeKilocalories" in stats + + +@pytest.mark.vcr +def test_user_summary(garmin): + garmin.login() + user_summary = garmin.get_user_summary(DATE) + assert "totalKilocalories" in user_summary + assert "activeKilocalories" in user_summary + + +@pytest.mark.vcr +def test_steps_data(garmin): + garmin.login() + steps_data = garmin.get_steps_data(DATE)[0] + assert "steps" in steps_data + + +@pytest.mark.vcr +def test_floors(garmin): + garmin.login() + floors_data = garmin.get_floors(DATE) + assert "floorValuesArray" in floors_data + + +@pytest.mark.vcr +def test_daily_steps(garmin): + garmin.login() + daily_steps = garmin.get_daily_steps(DATE, DATE)[0] + assert "calendarDate" in daily_steps + assert "totalSteps" in daily_steps + assert "stepGoal" in daily_steps + + +@pytest.mark.vcr +def test_heart_rates(garmin): + garmin.login() + heart_rates = garmin.get_heart_rates(DATE) + assert "calendarDate" in heart_rates + assert "restingHeartRate" in heart_rates + + +@pytest.mark.vcr +def test_stats_and_body(garmin): + garmin.login() + stats_and_body = garmin.get_stats_and_body(DATE) + assert "calendarDate" in stats_and_body + assert "metabolicAge" in stats_and_body + + +@pytest.mark.vcr +def test_body_composition(garmin): + garmin.login() + body_composition = garmin.get_body_composition(DATE) + assert "totalAverage" in body_composition + assert "metabolicAge" in body_composition["totalAverage"] + + +@pytest.mark.vcr +def test_body_battery(garmin): + garmin.login() + body_battery = garmin.get_body_battery(DATE)[0] + assert "date" in body_battery + assert "charged" in body_battery + + +@pytest.mark.vcr +def test_hydration_data(garmin): + garmin.login() + hydration_data = garmin.get_hydration_data(DATE) + assert hydration_data + assert "calendarDate" in hydration_data + + +@pytest.mark.vcr +def test_respiration_data(garmin): + garmin.login() + respiration_data = garmin.get_respiration_data(DATE) + assert "calendarDate" in respiration_data + assert "avgSleepRespirationValue" in respiration_data + + +@pytest.mark.vcr +def test_spo2_data(garmin): + garmin.login() + spo2_data = garmin.get_spo2_data(DATE) + assert "calendarDate" in spo2_data + assert "averageSpO2" in spo2_data + + +@pytest.mark.vcr +def test_hrv_data(garmin): + garmin.login() + hrv_data = garmin.get_hrv_data(DATE) + assert "hrvSummary" in hrv_data + assert "weeklyAvg" in hrv_data["hrvSummary"] + + +@pytest.mark.vcr +def test_download_activity(garmin): + garmin.login() + activity_id = "11998957007" + activity = garmin.download_activity(activity_id) + assert activity