diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e27a769..81a2668 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,10 +38,10 @@ jobs: pip install -e . pip install -r requirements-dev.txt - # - name: Lint with ruff - # run: | - # ruff check . - # ruff format --check . + - name: Lint with ruff + run: | + ruff check . + ruff format --check . - name: Test with pytest run: | diff --git a/README.md b/README.md index 46bcbbd..6f50f44 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,27 @@ A significant focus of this project has been ensuring compatibility with the ori This approach ensures that the Python implementation produces results consistent with the original R package. -## Unit Test Status +### Input & Output +The implementation maintains compatibility with the R version while following Python best practices. The metrics can be used as: + +```Python +import iglu_python ias iglu + +# With DataFrame input +result_df = iglu.cv_glu(data) # data should have 'id', 'time', and 'gl' columns +# Return DataFrame with "id' and column(s) with value(s) + +# With Series input (some metrics require Series with DateTimeIndex) +result_float = iglu.cv_glu(glucose_series) # just glucose values +# returns a single float value + +# Same with function that support list or ndarray +result_float = iglu.cv_glu(glucose_list) # list of glucose values +# returns a single float value + +``` + +## IGLU-R Compatibility Test Status The current version of IGLU-PYTHON is test-compatible with IGLU-R v4.2.2 Unless noted, IGLU-R test compatability is considered successful if it achieves precision of 0.001 @@ -69,25 +89,15 @@ Unless noted, IGLU-R test compatability is considered successful if it achieves | process_data | Data Pre-Processor | ✅ | | CGMS2DayByDay |Interpolate glucose input| ✅ | -### Input & Output -The implementation maintains compatibility with the R version while following Python best practices. The metrics can be used as: - -```Python -import iglu_python ias iglu - -# With DataFrame input -result_df = iglu.cv_glu(data) # data should have 'id', 'time', and 'gl' columns -# Return DataFrame with "id' and column(s) with value(s) +## Extended functionality +IGLU_PYTHON extends beyond the capabilities of the original IGLU-R package by offering enhanced functionality and improved user experience. We believe that combining these extended features with the proven reliability of IGLU-R creates a powerful synergy that benefits both the research community and wide software developers community. -# With Series input (some metrics require Series with DateTimeIndex) -result_float = iglu.cv_glu(glucose_series) # just glucose values -# returns a single float value -# Same with function that support list or ndarray -result_float = iglu.cv_glu(glucose_list) # list of glucose values -# returns a single float value -``` +| Function | Description | +|-------------------|------------------------------------------| +| load_libre() | Load Timeseries from Libre device file (CGM reading converted into mg/dL) +| load_dexcom() | Load Timeseries from Dexcom device file (CGM reading converted into mg/dL) # Installation diff --git a/iglu_python/__init__.py b/iglu_python/__init__.py index fbc7b95..7319042 100644 --- a/iglu_python/__init__.py +++ b/iglu_python/__init__.py @@ -9,6 +9,7 @@ from .cv_measures import cv_measures from .ea1c import ea1c from .episode_calculation import episode_calculation +from .extension.load_data import load_dexcom, load_libre from .gmi import gmi from .grade import grade from .grade_eugly import grade_eugly @@ -74,6 +75,8 @@ "iqr_glu", "j_index", "lbgi", + "load_dexcom", + "load_libre", "mad_glu", "mag", "mage", diff --git a/iglu_python/above_percent.py b/iglu_python/above_percent.py index bbdb9d6..3d0fb3e 100644 --- a/iglu_python/above_percent.py +++ b/iglu_python/above_percent.py @@ -7,9 +7,9 @@ def above_percent( - data: Union[pd.DataFrame, pd.Series, list,np.ndarray], + data: Union[pd.DataFrame, pd.Series, list, np.ndarray], targets_above: List[int] = None, -) -> pd.DataFrame|dict[str:float]: +) -> pd.DataFrame | dict[str:float]: """ Calculate percentage of values above target thresholds. @@ -61,12 +61,11 @@ def above_percent( # Handle Series input if targets_above is None: targets_above = [140, 180, 250] - if isinstance(data, (pd.Series, list,np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (list, np.ndarray)): data = pd.Series(data) return above_percent_single(data, targets_above) - # Handle DataFrame input data = check_data_columns(data) targets_above = [int(t) for t in targets_above] @@ -83,9 +82,10 @@ def above_percent( # Convert to DataFrame df = pd.DataFrame(result) - df = df[['id'] + [col for col in df.columns if col != 'id']] + df = df[["id"] + [col for col in df.columns if col != "id"]] return df + def above_percent_single(data: pd.Series, targets_above: List[int] = None) -> dict[str:float]: """ Calculate percentage of values above target thresholds for a single series/subject. diff --git a/iglu_python/active_percent.py b/iglu_python/active_percent.py index b1cfbfa..2e4ef48 100644 --- a/iglu_python/active_percent.py +++ b/iglu_python/active_percent.py @@ -14,7 +14,7 @@ def active_percent( range_type: str = "automatic", ndays: int = 14, consistent_end_date: Optional[Union[str, datetime]] = None, -) -> pd.DataFrame|dict[str:float]: +) -> pd.DataFrame | dict[str:float]: """ Calculate percentage of time CGM was active. @@ -86,21 +86,16 @@ def active_percent( # Process each subject for subject in data["id"].unique(): # Filter data for current subject and remove NA values - sub_data = ( - data[data["id"] == subject] - .dropna(subset=["gl", "time"]) - .sort_values("time") - ) + sub_data = data[data["id"] == subject].dropna(subset=["gl", "time"]).sort_values("time") timeseries = sub_data.set_index("time")["gl"] active_percent_dict = active_percent_single(timeseries, dt0, tz, range_type, ndays, consistent_end_date) active_percent_dict["id"] = subject active_perc_data.append(active_percent_dict) - # Convert to DataFrame df = pd.DataFrame(active_perc_data) - df = df[['id'] + [col for col in df.columns if col != 'id']] + df = df[["id"] + [col for col in df.columns if col != "id"]] return df @@ -127,9 +122,7 @@ def active_percent_single( return {"active_percent": 0, "ndays": 0, "start_date": None, "end_date": None} # Calculate time differences between consecutive measurements - time_diffs = np.array( - data.index.diff().total_seconds() / 60 - ) # Convert to minutes + time_diffs = np.array(data.index.diff().total_seconds() / 60) # Convert to minutes # Automatically determine dt0 if not provided if dt0 is None: @@ -154,9 +147,7 @@ def active_percent_single( ndays = (max_time - min_time).total_seconds() / (24 * 3600) # Calculate active percentage - active_percent = ( - (theoretical_gl_vals - missing_gl_vals) / theoretical_gl_vals - ) * 100 + active_percent = ((theoretical_gl_vals - missing_gl_vals) / theoretical_gl_vals) * 100 elif range_type == "manual": # Handle consistent end date if provided if consistent_end_date is not None: @@ -178,6 +169,3 @@ def active_percent_single( raise ValueError(f"Invalid range_type: {range_type}") return {"active_percent": active_percent, "ndays": round(ndays, 1), "start_date": min_time, "end_date": max_time} - - - diff --git a/iglu_python/adrr.py b/iglu_python/adrr.py index cf26023..3e65c8f 100644 --- a/iglu_python/adrr.py +++ b/iglu_python/adrr.py @@ -1,11 +1,10 @@ - import numpy as np import pandas as pd from .utils import check_data_columns -def adrr(data: pd.DataFrame|pd.Series) -> pd.DataFrame|float: +def adrr(data: pd.DataFrame | pd.Series) -> pd.DataFrame | float: """ Calculate average daily risk range (ADRR) @@ -52,7 +51,6 @@ def adrr(data: pd.DataFrame|pd.Series) -> pd.DataFrame|float: >>> iglu.adrr(data) """ - # Validate input if isinstance(data, pd.Series): if not isinstance(data.index, pd.DatetimeIndex): @@ -61,15 +59,13 @@ def adrr(data: pd.DataFrame|pd.Series) -> pd.DataFrame|float: data = check_data_columns(data) - data.set_index("time", inplace=True,drop=True) - out = data.groupby("id").agg( - ADRR = ("gl", lambda x: adrr_single(x)) - ).reset_index() + data.set_index("time", inplace=True, drop=True) + out = data.groupby("id").agg(ADRR=("gl", lambda x: adrr_single(x))).reset_index() return out -def adrr_single(data: pd.DataFrame|pd.Series) -> float: +def adrr_single(data: pd.DataFrame | pd.Series) -> float: """Internal function to calculate ADRR for a single subject or timeseries of glucose values""" if isinstance(data, pd.Series): @@ -85,11 +81,10 @@ def adrr_single(data: pd.DataFrame|pd.Series) -> float: return np.nan # Group by date and calculate daily risk for each day - daily_risks = data_filtered.groupby(data_filtered.index.date).apply( - lambda x: _calculate_daily_risk(x) - ) + daily_risks = data_filtered.groupby(data_filtered.index.date).apply(lambda x: _calculate_daily_risk(x)) return daily_risks.mean() + def _calculate_daily_risk(gl: pd.Series) -> float: """Calculate daily risk range for a single day and subject""" diff --git a/iglu_python/auc.py b/iglu_python/auc.py index e0cbdb4..9429100 100644 --- a/iglu_python/auc.py +++ b/iglu_python/auc.py @@ -1,4 +1,3 @@ - import numpy as np import pandas as pd @@ -60,7 +59,7 @@ def auc(data: pd.DataFrame, tz: str = "") -> pd.DataFrame: if not isinstance(data.index, pd.DatetimeIndex): raise ValueError("Series must have a DatetimeIndex") - auc = auc_single(data,tz=tz) + auc = auc_single(data, tz=tz) return auc # Check data format and convert time to datetime @@ -70,13 +69,14 @@ def auc(data: pd.DataFrame, tz: str = "") -> pd.DataFrame: result = [] for subject in data["id"].unique(): subject_data = data[data["id"] == subject] - hourly_auc = auc_single(subject_data,tz=tz) + hourly_auc = auc_single(subject_data, tz=tz) result.append({"id": subject, "hourly_auc": hourly_auc}) # Convert to DataFrame return pd.DataFrame(result) -def auc_single(subject_data: pd.DataFrame|pd.Series,tz:str = "") -> float: + +def auc_single(subject_data: pd.DataFrame | pd.Series, tz: str = "") -> float: """Calculate AUC for a single subject""" # Get interpolated data using CGMS2DayByDay gd2d, actual_dates, dt0 = CGMS2DayByDay(subject_data, tz=tz) @@ -84,32 +84,26 @@ def auc_single(subject_data: pd.DataFrame|pd.Series,tz:str = "") -> float: # Convert gd2d to DataFrame input_data = gd2d_to_df(gd2d, actual_dates, dt0) if is_iglu_r_compatible(): - input_data['day'] = input_data['time'].dt.floor('d') - input_data['gl_next'] = input_data['gl'].shift(-1) + input_data["day"] = input_data["time"].dt.floor("d") + input_data["gl_next"] = input_data["gl"].shift(-1) each_day_area = input_data.groupby("day").apply( - lambda x: np.nansum( - (dt0/60)*(x["gl"].values + x["gl_next"].values) / 2 - ), - include_groups=False + lambda x: np.nansum((dt0 / 60) * (x["gl"].values + x["gl_next"].values) / 2), include_groups=False ) # calculate number of not nan trapezoids in total (number of not nan gl and gl_next) n_trapezoids = (~np.isnan(input_data["gl"]) & ~np.isnan(input_data["gl_next"])).sum() - hours = dt0/60 * n_trapezoids + hours = dt0 / 60 * n_trapezoids daily_area = each_day_area.sum() - hourly_avg = daily_area/hours + hourly_avg = daily_area / hours return hourly_avg else: # Add hour column by rounding time to nearest hour - input_data['hour'] = input_data['time'].dt.floor('h') + input_data["hour"] = input_data["time"].dt.floor("h") - input_data['gl_next'] = input_data['gl'].shift(-1) + input_data["gl_next"] = input_data["gl"].shift(-1) # Calculate AUC for each hour using trapezoidal rule (mg*min/dL) hourly_auc = input_data.groupby("hour").apply( - lambda x: np.nansum( - (dt0/60)*(x["gl"].values + x["gl_next"].values) / 2 - ), - include_groups=False + lambda x: np.nansum((dt0 / 60) * (x["gl"].values + x["gl_next"].values) / 2), include_groups=False ) # 0 mean no data in this hour, replace with nan hourly_auc = hourly_auc.replace(0, np.nan) diff --git a/iglu_python/below_percent.py b/iglu_python/below_percent.py index 2632bc1..4dbf457 100644 --- a/iglu_python/below_percent.py +++ b/iglu_python/below_percent.py @@ -7,8 +7,8 @@ def below_percent( - data: Union[pd.DataFrame, pd.Series, list,np.ndarray], targets_below: List[int] = None -) -> pd.DataFrame|dict[str:float]: + data: Union[pd.DataFrame, pd.Series, list, np.ndarray], targets_below: List[int] = None +) -> pd.DataFrame | dict[str:float]: """ Calculate percentage of values below target thresholds. @@ -60,12 +60,11 @@ def below_percent( # Handle Series input if targets_below is None: targets_below = [54, 70] - if isinstance(data, (pd.Series, list,np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (list, np.ndarray)): data = pd.Series(data) return below_percent_single(data, targets_below) - # Handle DataFrame input data = check_data_columns(data) @@ -82,9 +81,10 @@ def below_percent( # Convert to DataFrame df = pd.DataFrame(result) - df = df[['id'] + [col for col in df.columns if col != 'id']] + df = df[["id"] + [col for col in df.columns if col != "id"]] return df + def below_percent_single(data: pd.Series, targets_below: List[int] = None) -> dict[str:float]: """ Calculate percentage of values below target thresholds for a single series/subject. @@ -106,4 +106,3 @@ def below_percent_single(data: pd.Series, targets_below: List[int] = None) -> di percentages[f"below_{target}"] = (below_count / total_readings) * 100 return percentages - diff --git a/iglu_python/cogi.py b/iglu_python/cogi.py index ab56908..aff6ee4 100644 --- a/iglu_python/cogi.py +++ b/iglu_python/cogi.py @@ -10,10 +10,10 @@ def cogi( - data: Union[pd.DataFrame, pd.Series, list,np.ndarray], + data: Union[pd.DataFrame, pd.Series, list, np.ndarray], targets: List[int] = None, weights: List[float] = None, -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate Coefficient of Glucose Irregularity (COGI). @@ -81,12 +81,11 @@ def cogi( data = check_data_columns(data) - out = data.groupby("id").agg( - COGI=('gl', lambda x: cogi_single(x, targets, weights)) - ).reset_index() + out = data.groupby("id").agg(COGI=("gl", lambda x: cogi_single(x, targets, weights))).reset_index() return out + def cogi_single(data: pd.Series, targets: List[int] = None, weights: List[float] = None) -> float: """Calculate COGI for a single subject""" # Calculate components @@ -110,7 +109,6 @@ def cogi_single(data: pd.Series, targets: List[int] = None, weights: List[float] return weighted_features * 100 # Convert to percentage - def weight_features( feature: Union[float, pd.Series, list], scale_range: List[float], @@ -122,26 +120,19 @@ def weight_features( with the same number of rows (or length) as the input, with values clipped (or "inverse" clipped) so that they are between 0 and 1.""" if isinstance(feature, pd.Series): - scaled = (feature - min(scale_range)) / ( - max(scale_range) - min(scale_range) - ) + scaled = (feature - min(scale_range)) / (max(scale_range) - min(scale_range)) if increasing: out = scaled.clip(lower=0, upper=1) else: out = (1 - scaled).clip(lower=0, upper=1) elif isinstance(feature, list): - scaled = [ - (x - min(scale_range)) / (max(scale_range) - min(scale_range)) - for x in feature - ] + scaled = [(x - min(scale_range)) / (max(scale_range) - min(scale_range)) for x in feature] if increasing: out = [min(1, max(0, x)) for x in scaled] else: out = [min(1, max(0, 1 - x)) for x in scaled] else: - scaled = (feature - min(scale_range)) / ( - max(scale_range) - min(scale_range) - ) + scaled = (feature - min(scale_range)) / (max(scale_range) - min(scale_range)) if increasing: out = min(1, max(0, scaled)) else: diff --git a/iglu_python/conga.py b/iglu_python/conga.py index 4beda95..20f18c0 100644 --- a/iglu_python/conga.py +++ b/iglu_python/conga.py @@ -6,9 +6,7 @@ from .utils import CGMS2DayByDay, check_data_columns -def conga( - data: Union[pd.DataFrame, pd.Series], n: int = 24, tz: str = "" -) -> pd.DataFrame|float: +def conga(data: Union[pd.DataFrame, pd.Series], n: int = 24, tz: str = "") -> pd.DataFrame | float: """ Calculate Continuous Overall Net Glycemic Action (CONGA). @@ -69,14 +67,13 @@ def conga( data = check_data_columns(data) # Calculate CONGA for each subject - data.set_index("time", inplace=True,drop=True) - out = data.groupby('id').agg( - CONGA = ("gl", lambda x: conga_single(x, hours=n, tz=tz)) - ).reset_index() + data.set_index("time", inplace=True, drop=True) + out = data.groupby("id").agg(CONGA=("gl", lambda x: conga_single(x, hours=n, tz=tz))).reset_index() return out -def conga_single(data: pd.DataFrame|pd.Series, hours: int = 1, tz: str = "") -> float: + +def conga_single(data: pd.DataFrame | pd.Series, hours: int = 1, tz: str = "") -> float: """Calculate CONGA for a single subject""" # Convert data to day-by-day format # Missing values will be linearly interpolated when close enough to non-missing values. diff --git a/iglu_python/cv_glu.py b/iglu_python/cv_glu.py index 9a20a31..c98a4d6 100644 --- a/iglu_python/cv_glu.py +++ b/iglu_python/cv_glu.py @@ -56,8 +56,6 @@ def cv_glu(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> Union[pd.D data = data.dropna() # Calculate CV for each subject - out = data.groupby('id').agg( - CV=('gl', lambda x: 100 * x.std() / x.mean()) - ).reset_index() + out = data.groupby("id").agg(CV=("gl", lambda x: 100 * x.std() / x.mean())).reset_index() return out diff --git a/iglu_python/cv_measures.py b/iglu_python/cv_measures.py index 7300a7b..8dbfc4e 100644 --- a/iglu_python/cv_measures.py +++ b/iglu_python/cv_measures.py @@ -17,7 +17,7 @@ from .utils import CGMS2DayByDay, check_data_columns -def cv_measures(data, dt0=None, inter_gap=45, tz="")->pd.DataFrame|dict[str:float]: +def cv_measures(data, dt0=None, inter_gap=45, tz="") -> pd.DataFrame | dict[str:float]: """Calculate Coefficient of Variation subtypes (CVmean and CVsd). The function cv_measures produces CV subtype values in a pandas DataFrame object. @@ -60,43 +60,36 @@ def cv_measures(data, dt0=None, inter_gap=45, tz="")->pd.DataFrame|dict[str:floa # Check and prepare data data = check_data_columns(data) - # Process each subject results = [] - for subject_id in data['id'].unique(): - subject_data = data[data['id'] == subject_id] + for subject_id in data["id"].unique(): + subject_data = data[data["id"] == subject_id] results_dict = _calculate_series_cv(subject_data, dt0=dt0, inter_gap=inter_gap, tz=tz) - results.append({ - 'id': subject_id, - 'CVmean': results_dict['CVmean'], - 'CVsd': results_dict['CVsd'] - }) + results.append({"id": subject_id, "CVmean": results_dict["CVmean"], "CVsd": results_dict["CVsd"]}) return pd.DataFrame(results) -def _calculate_series_cv(subject_data: pd.DataFrame|pd.Series, dt0=None, inter_gap=45, tz="") -> dict[str:float]: + +def _calculate_series_cv(subject_data: pd.DataFrame | pd.Series, dt0=None, inter_gap=45, tz="") -> dict[str:float]: """Calculate CV for series/single subject input""" # Convert to day-by-day format - gd2d,active_days,dt0 = CGMS2DayByDay(subject_data, dt0=dt0, inter_gap=inter_gap, tz=tz) + gd2d, active_days, dt0 = CGMS2DayByDay(subject_data, dt0=dt0, inter_gap=inter_gap, tz=tz) # gd2d is two dimensional array - 1st dimension is day, 2nd dimension is time point # active_days is a list of days that have at least 2 non-missing values # dt0 is the time frequency for interpolation in minutes # calculate devioation and median for each day - daily_deviations = np.apply_along_axis(np.nanstd, 1, gd2d,ddof=1) + daily_deviations = np.apply_along_axis(np.nanstd, 1, gd2d, ddof=1) daily_mean = np.apply_along_axis(np.nanmean, 1, gd2d) - cv = daily_deviations *100 / daily_mean + cv = daily_deviations * 100 / daily_mean # calculate mean of daily deviations cv_mean = np.nanmean(cv) - cv_sd = np.nanstd(cv,ddof=1) + cv_sd = np.nanstd(cv, ddof=1) - return { - 'CVmean': cv_mean, - 'CVsd': cv_sd - } + return {"CVmean": cv_mean, "CVsd": cv_sd} diff --git a/iglu_python/ea1c.py b/iglu_python/ea1c.py index b9bca91..f7c5e1a 100644 --- a/iglu_python/ea1c.py +++ b/iglu_python/ea1c.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def ea1c(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.DataFrame|float: +def ea1c(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.DataFrame | float: """ Calculate estimated A1C (eA1C) values. @@ -56,14 +56,11 @@ def ea1c(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.DataFrame data = pd.Series(data) return ea1c_single(data) - # Handle DataFrame input data = check_data_columns(data) # Calculate eA1C for each subject - out = data.groupby('id').agg( - eA1C = ("gl", lambda x: ea1c_single(x)) - ).reset_index() + out = data.groupby("id").agg(eA1C=("gl", lambda x: ea1c_single(x))).reset_index() return out diff --git a/iglu_python/episode_calculation.py b/iglu_python/episode_calculation.py index 927047d..56af7f8 100644 --- a/iglu_python/episode_calculation.py +++ b/iglu_python/episode_calculation.py @@ -127,28 +127,32 @@ def episode_calculation( # Check duration parameters if dur_length > inter_gap: print( - "Warning: Interpolation gap parameter less than episode duration, " - "data gaps may cause incorrect computation" + "Warning: Interpolation gap parameter less than episode duration, data gaps may cause incorrect computation" ) episode_data_df = pd.DataFrame( columns=[ - 'id', 'time', 'gl', 'segment', - 'lv1_hypo', 'lv2_hypo', 'lv1_hyper', 'lv2_hyper', - 'ext_hypo', 'lv1_hypo_excl', 'lv1_hyper_excl' + "id", + "time", + "gl", + "segment", + "lv1_hypo", + "lv2_hypo", + "lv1_hyper", + "lv2_hyper", + "ext_hypo", + "lv1_hypo_excl", + "lv1_hyper_excl", ] ) episode_summary_df = pd.DataFrame( - columns=[ - 'id', 'type', 'level', 'avg_ep_per_day', - 'avg_ep_duration', 'avg_ep_gl', 'total_episodes' - ] + columns=["id", "type", "level", "avg_ep_per_day", "avg_ep_duration", "avg_ep_gl", "total_episodes"] ) # Process each subject ID separately - for subject_id in data['id'].unique(): + for subject_id in data["id"].unique(): # Get data for this subject - subject_data = data[data['id'] == subject_id].copy() + subject_data = data[data["id"] == subject_id].copy() # Calculate episodes for this subject subject_summary, subject_episode_data = episode_single( @@ -164,8 +168,8 @@ def episode_calculation( tz=tz, ) - subject_summary['id'] = subject_id - subject_episode_data['id'] = subject_id + subject_summary["id"] = subject_id + subject_episode_data["id"] = subject_id # Append to main dataframes if episode_data_df.empty: @@ -178,13 +182,12 @@ def episode_calculation( else: episode_summary_df = pd.concat([episode_summary_df, subject_summary], ignore_index=True) - - if return_data: return episode_summary_df, episode_data_df else: return episode_summary_df + def episode_single( data: pd.DataFrame, lv1_hypo: float, @@ -236,25 +239,22 @@ def episode_single( dt0 = gd2d_tuple[2] if is_iglu_r_compatible(): - day_one = pd.to_datetime(gd2d_tuple[1][0]).tz_localize(None) # make in naive-timezone - day_one = day_one.tz_localize('UTC') # this is how IGLU_R works - if tz and tz!="": + day_one = pd.to_datetime(gd2d_tuple[1][0]).tz_localize(None) # make in naive-timezone + day_one = day_one.tz_localize("UTC") # this is how IGLU_R works + if tz and tz != "": day_one = day_one.tz_convert(tz) else: local_tz = get_local_tz() day_one = day_one.tz_convert(local_tz) ndays = len(gd2d_tuple[1]) # generate grid times by starting from day one and cumulatively summing - time_ip = pd.date_range(start=day_one + pd.Timedelta(minutes=dt0), periods=int(ndays * 24 * 60 /dt0), - freq=f"{dt0}min") + time_ip = pd.date_range( + start=day_one + pd.Timedelta(minutes=dt0), periods=int(ndays * 24 * 60 / dt0), freq=f"{dt0}min" + ) data_ip = gd2d_tuple[0].flatten().tolist() - new_data = pd.DataFrame({ - "time": time_ip, - "gl": data_ip - }) + new_data = pd.DataFrame({"time": time_ip, "gl": data_ip}) else: - new_data = gd2d_to_df(gd2d_tuple[0],gd2d_tuple[1],gd2d_tuple[2]) - + new_data = gd2d_to_df(gd2d_tuple[0], gd2d_tuple[1], gd2d_tuple[2]) # Check duration parameters if dur_length % dt0 != 0: @@ -268,7 +268,7 @@ def episode_single( # Step 1: Create boolean mask for NA values # R: na_idx = is.na(new_data$gl) - na_idx = new_data['gl'].isna() + na_idx = new_data["gl"].isna() # Step 2: Run-length encoding to find consecutive runs # R: segment_rle = rle(na_idx)$lengths @@ -282,14 +282,13 @@ def episode_single( # R: segment_data$segment = rep(1:length(segment_rle), segment_rle) segment_ids = np.repeat( range(1, len(segment_rle) + 1), # 1:length(segment_rle) - segment_rle # repeat counts + segment_rle, # repeat counts ) - segment_data['segment'] = segment_ids + segment_data["segment"] = segment_ids # Step 5: Remove rows with NA glucose values # R: segment_data = segment_data[!is.na(segment_data$gl), ] - segment_data = segment_data[~segment_data['gl'].isna()].reset_index(drop=True) - + segment_data = segment_data[~segment_data["gl"].isna()].reset_index(drop=True) # Classify events for each segment ep_per_seg = ( @@ -301,29 +300,26 @@ def episode_single( "lv2_hypo": event_class(x, "hypo", lv2_hypo, dur_idx, end_idx), "lv1_hyper": event_class(x, "hyper", lv1_hyper, dur_idx, end_idx), "lv2_hyper": event_class(x, "hyper", lv2_hyper, dur_idx, end_idx), - "ext_hypo": event_class( - x, "hypo", lv1_hypo, int(120 / dt0) + 1, end_idx - ), + "ext_hypo": event_class(x, "hypo", lv1_hypo, int(120 / dt0) + 1, end_idx), } ), - include_groups=False + include_groups=False, ) .reset_index() - .drop(columns=['level_1']) + .drop(columns=["level_1"]) ) - # Add exclusive labels using the correct original logic without DeprecationWarning # For hypo exclusion: group by both segment and lv1_hypo, set to 0 if any lv2_hypo > 0 in that group def calculate_exclusion(df, lv1_col, lv2_col): """Calculate exclusion labels for lv1 episodes based on lv2 episodes in same group""" df = df.copy() - df['group_id'] = df.groupby(['segment', lv1_col]).ngroup() - group_has_lv2 = df.groupby('group_id')[lv2_col].transform(lambda x: (x > 0).any()) + df["group_id"] = df.groupby(["segment", lv1_col]).ngroup() + group_has_lv2 = df.groupby("group_id")[lv2_col].transform(lambda x: (x > 0).any()) return df[lv1_col].where(~group_has_lv2, 0) - ep_per_seg['lv1_hypo_excl'] = calculate_exclusion(ep_per_seg, 'lv1_hypo', 'lv2_hypo') - ep_per_seg['lv1_hyper_excl'] = calculate_exclusion(ep_per_seg, 'lv1_hyper', 'lv2_hyper') + ep_per_seg["lv1_hypo_excl"] = calculate_exclusion(ep_per_seg, "lv1_hypo", "lv2_hypo") + ep_per_seg["lv1_hyper_excl"] = calculate_exclusion(ep_per_seg, "lv1_hyper", "lv2_hyper") full_segment_df = pd.concat([segment_data, ep_per_seg.drop(["segment"], axis=1)], axis=1) @@ -331,6 +327,7 @@ def calculate_exclusion(df, lv1_col, lv2_col): summary_df = episode_summary(full_segment_df, dt0) return summary_df, full_segment_df + def event_class( data: pd.DataFrame, level_type: str, @@ -391,29 +388,25 @@ def event_class( lambda x: pd.DataFrame( { # possibly event; where duration is met - "pos_start": [x["level"].iloc[0] and (len(x) >= event_duration)]*len(x), + "pos_start": [x["level"].iloc[0] and (len(x) >= event_duration)] * len(x), # if possible event, add start on first index of event "start": ( - ["start" - if (x["level"].iloc[0] and len(x) >= event_duration) - else None] + [None]*(len(x)-1) + ["start" if (x["level"].iloc[0] and len(x) >= event_duration) else None] + [None] * (len(x) - 1) ), # add possible ends (always need to check for end duration) - "pos_end": [not x["level"].iloc[0] and (len(x) >= end_duration)]*len(x), + "pos_end": [not x["level"].iloc[0] and (len(x) >= end_duration)] * len(x), "end": ( - ["end" - if (not x["level"].iloc[0] and len(x) >= end_duration) - else None] + [None]*(len(x)-1) + ["end" if (not x["level"].iloc[0] and len(x) >= end_duration) else None] + [None] * (len(x) - 1) ), } ), - include_groups=False + include_groups=False, ) .reset_index() - .drop(columns=['level_1']) + .drop(columns=["level_1"]) ) - annotated = pd.concat([annotated,annotated_grouped.drop(["event"], axis=1)], axis=1) + annotated = pd.concat([annotated, annotated_grouped.drop(["event"], axis=1)], axis=1) ### for each possible end find the matching start # Get start and end positions @@ -473,16 +466,13 @@ def lv1_excl(data: pd.DataFrame) -> np.ndarray: # Calculate exclusive labels excl = grouped.apply( - lambda x: pd.DataFrame( - { - "excl":[0 if (x[lv2_first].values > 0).any() else x[lv1_first].iloc[0]]*len(x) - }), - include_groups=False + lambda x: pd.DataFrame({"excl": [0 if (x[lv2_first].values > 0).any() else x[lv1_first].iloc[0]] * len(x)}), + include_groups=False, ) excl = excl.reset_index() - return excl[['segment','excl']] + return excl[["segment", "excl"]] def episode_summary(data: pd.DataFrame, dt0: float) -> pd.DataFrame: @@ -502,12 +492,10 @@ def episode_summary(data: pd.DataFrame, dt0: float) -> pd.DataFrame: Summary statistics for each episode type """ - def episode_summary_helper( - data: pd.DataFrame, level_label: str, dt0: float - ) -> List[float]: + def episode_summary_helper(data: pd.DataFrame, level_label: str, dt0: float) -> List[float]: """Helper function to calculate summary for one episode type""" # Select relevant columns - data = data[[ "time", "gl", "segment", level_label]].copy() + data = data[["time", "gl", "segment", level_label]].copy() data.columns = ["time", "gl", "segment", "event"] # If no events, return zeros/NA @@ -516,11 +504,7 @@ def episode_summary_helper( # Calculate summary metrics events = data[data["event"] != 0][["gl", "segment", "event"]] - data_sum = ( - events.groupby(["segment", "event"]) - .agg({"gl": ["count", "mean"]}) - .reset_index() - ) + data_sum = events.groupby(["segment", "event"]).agg({"gl": ["count", "mean"]}).reset_index() # Calculate metrics avg_ep_per_day = len(data_sum) / (len(data) * dt0 / 60 / 24) @@ -556,6 +540,7 @@ def episode_summary_helper( return output + def _rle_lengths(boolean_series): """Python equivalent of R's rle()$lengths""" # Find where values change diff --git a/iglu_python/extension/load_data.py b/iglu_python/extension/load_data.py new file mode 100644 index 0000000..520775c --- /dev/null +++ b/iglu_python/extension/load_data.py @@ -0,0 +1,178 @@ +""" +This module is to load CGM timeseries from device specific files. +It is inspired by https://github.com/cafoala/diametrics/blob/main/src/diametrics/transform.py +""" + +from pathlib import Path + +import pandas as pd + + +def load_libre(file_path: str) -> pd.Series: + """ + Load Libre timeseries from file. + + Parameters + ---------- + file_path : str + Path to the Libre device file. + + Returns + ------- + pd.Series + Series with datetime index and glucose values.(in mg/dL) + + Examples + -------- + >>> load_libre("tests/data/libre_amer_01.csv") + """ + df = _open_file(file_path) + + # Set third row as column headers + df.columns = df.iloc[2] + # Drop top rows + df = df.iloc[3:] + df.reset_index(inplace=True, drop=True) + # Keep important columns based on column names + convert = False + if "Historic Glucose(mmol/L)" in df.columns: + df = df.loc[:, ("Meter Timestamp", "Historic Glucose(mmol/L)", "Scan Glucose(mmol/L)")] + format = "%d-%m-%Y %H:%M" + convert = True + elif "Historic Glucose(mg/dL)" in df.columns: + df = df.loc[:, ("Meter Timestamp", "Historic Glucose(mg/dL)", "Scan Glucose(mg/dL)")] + format = "%m-%d-%Y %H:%M" + elif "Historic Glucose mmol/L" in df.columns: + df = df.loc[:, ("Device Timestamp", "Historic Glucose mmol/L", "Scan Glucose mmol/L")] + format = "%d-%m-%Y %I:%M %p" + convert = True + else: + df = df = df.loc[:, ("Device Timestamp", "Historic Glucose mg/dL", "Scan Glucose mg/dL")] + format = "%m-%d-%Y %I:%M %p" + # Rename columns + df.columns = ["time", "glc", "scan_glc"] + + # Convert 'time' column to datetime + df["time"] = pd.to_datetime(df["time"], format=format) + + # Convert glucose values to numeric + df["glc"] = pd.to_numeric(df["glc"], errors="coerce") + + # convert to mg/dL if needed + if convert: + df["glc"] = df["glc"] * 18.01559 + + # Drop NaN values and sort by 'time' + df = df.dropna(subset=["time", "glc"]).sort_values("time").reset_index(drop=True) + + # convert into timeseries + timeseries = df.set_index("time")["glc"] + + return timeseries + + +def load_dexcom(file_path: str) -> pd.Series: + """ + Load Dexcom timeseries from file. + + Parameters + ---------- + file_path : str + Path to the Dexcom device file. + + Returns + ------- + pd.Series + Series with datetime index and glucose values (in mg/dL) + + Examples + -------- + >>> load_dexcom("tests/data/dexcom_eur_01.xlsx") + """ + df = _open_file(file_path) + + # Set first row as column headers + df.columns = df.iloc[0] + # Drop top rows + df = df.iloc[1:] + df.reset_index(inplace=True, drop=True) + + # Find timestamp column + timestamp_cols = [col for col in df.columns if "Timestamp" in str(col)] + if not timestamp_cols: + raise ValueError("No timestamp column found in Dexcom data") + timestamp_col = timestamp_cols[0] + + # Find glucose column + glucose_cols = [col for col in df.columns if "Glucose" in str(col)] + if not glucose_cols: + raise ValueError("No glucose column found in Dexcom data") + glucose_col = glucose_cols[0] + + # Check if conversion is needed (mmol/L to mg/dL) + convert = False + if "mmol/L" in str(glucose_col): + convert = True + + # Select relevant columns + df = df.loc[:, [timestamp_col, glucose_col]] + + # Rename columns + df.columns = ["time", "glc"] + + # Convert 'time' column to datetime + df["time"] = pd.to_datetime(df["time"], errors="coerce") + + # Convert glucose values to numeric + df["glc"] = pd.to_numeric(df["glc"], errors="coerce") + + # Convert to mg/dL if needed + if convert: + df["glc"] = df["glc"] * 18.01559 + + # Drop NaN values and sort by 'time' + df = df.dropna(subset=["time", "glc"]).sort_values("time").reset_index(drop=True) + + # Convert into timeseries + timeseries = df.set_index("time")["glc"] + + return timeseries + + +def _open_file(filepath: str) -> pd.DataFrame: + """ + Open a file and read its contents into a pandas DataFrame. + + Args: + filepath (str): The path to the file. + + Returns: + pandas.DataFrame: The DataFrame containing the file data. + + Raises: + Exception: If an error occurs while reading the file. + """ + # TODO: handle S3 path + + if not Path(filepath).exists(): + raise FileNotFoundError(f"File not found: {filepath}") + + # Get file extension using basename + extension = Path(filepath).suffix + + try: + if extension == ".csv": + # Assume that the user uploaded a CSV file + df = pd.read_csv(filepath, header=None, names=list(range(0, 20))) + elif extension == ".xls" or extension == ".xlsx": + # Assume that the user uploaded an Excel file + df = pd.read_excel(filepath, header=None, names=list(range(0, 20))) + elif extension == ".txt" or extension == ".tsv": + # Assume that the user uploaded a text file + df = pd.read_table(filepath, header=None, names=list(range(0, 20))) + else: + raise ValueError(f"Unsupported file extension: {extension}") + + return df + except Exception as e: + raise ValueError(f"Error reading file: {filepath}") from e diff --git a/iglu_python/gmi.py b/iglu_python/gmi.py index 312b7d4..4450ae6 100644 --- a/iglu_python/gmi.py +++ b/iglu_python/gmi.py @@ -19,7 +19,7 @@ from iglu_python.utils import check_data_columns -def gmi(data: Union[pd.DataFrame, pd.Series, list]) -> float|pd.DataFrame: +def gmi(data: Union[pd.DataFrame, pd.Series, list]) -> float | pd.DataFrame: """Calculate GMI (Glucose Management Indicator). The function gmi produces GMI values in a pandas DataFrame object. @@ -54,8 +54,6 @@ def gmi(data: Union[pd.DataFrame, pd.Series, list]) -> float|pd.DataFrame: getattr(data, "is_vector", False) # Calculate GMI for each subject - out = data.groupby("id").agg( - GMI=("gl", lambda x: 3.31 + (0.02392 * x.mean())) - ).reset_index() + out = data.groupby("id").agg(GMI=("gl", lambda x: 3.31 + (0.02392 * x.mean()))).reset_index() return out diff --git a/iglu_python/grade.py b/iglu_python/grade.py index 3ebe98f..bc4868f 100644 --- a/iglu_python/grade.py +++ b/iglu_python/grade.py @@ -87,4 +87,3 @@ def _grade_formula(x: Union[pd.Series, np.ndarray]) -> Union[pd.Series, np.ndarr """ grade = 425 * (np.log10(np.log10(x / 18)) + 0.16) ** 2 return np.minimum(grade, 50) # Cap at 50 - diff --git a/iglu_python/grade_eugly.py b/iglu_python/grade_eugly.py index 8320198..82478ef 100644 --- a/iglu_python/grade_eugly.py +++ b/iglu_python/grade_eugly.py @@ -9,7 +9,7 @@ def grade_eugly( data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: int = 70, upper: int = 140 -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate percentage of GRADE score attributable to target range. @@ -69,9 +69,7 @@ def grade_eugly( data = check_data_columns(data) # Calculate GRADE euglycemia for each subject - out = data.groupby('id').agg( - GRADE_eugly = ("gl", lambda x: grade_eugly_single(x, lower, upper)) - ).reset_index() + out = data.groupby("id").agg(GRADE_eugly=("gl", lambda x: grade_eugly_single(x, lower, upper))).reset_index() return out diff --git a/iglu_python/grade_hyper.py b/iglu_python/grade_hyper.py index 3c60e44..bf3e22d 100644 --- a/iglu_python/grade_hyper.py +++ b/iglu_python/grade_hyper.py @@ -7,7 +7,7 @@ from .utils import check_data_columns -def grade_hyper(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], upper: int = 140) -> pd.DataFrame|float: +def grade_hyper(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], upper: int = 140) -> pd.DataFrame | float: """ Calculate percentage of GRADE score attributable to hyperglycemia. @@ -63,11 +63,10 @@ def grade_hyper(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], upper: i # Handle DataFrame input data = check_data_columns(data) - out = data.groupby('id').agg( - GRADE_hyper = ("gl", lambda x: grade_hyper_single(x, upper)) - ).reset_index() + out = data.groupby("id").agg(GRADE_hyper=("gl", lambda x: grade_hyper_single(x, upper))).reset_index() return out + def grade_hyper_single(data: pd.Series, upper: int = 140) -> float: """Calculate GRADE hyperglycemia for a single timeseries""" data = data.dropna() diff --git a/iglu_python/grade_hypo.py b/iglu_python/grade_hypo.py index 591a2a8..11ab319 100644 --- a/iglu_python/grade_hypo.py +++ b/iglu_python/grade_hypo.py @@ -7,7 +7,7 @@ from .utils import check_data_columns -def grade_hypo(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: int = 80) -> pd.DataFrame|float: +def grade_hypo(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: int = 80) -> pd.DataFrame | float: """ Calculate percentage of GRADE score attributable to hypoglycemia. @@ -64,12 +64,11 @@ def grade_hypo(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: in data = check_data_columns(data) # Calculate GRADE hypoglycemia for each subject - out = data.groupby('id').agg( - GRADE_hypo = ("gl", lambda x: grade_hypo_single(x, lower)) - ).reset_index() + out = data.groupby("id").agg(GRADE_hypo=("gl", lambda x: grade_hypo_single(x, lower))).reset_index() return out + def grade_hypo_single(data: pd.Series, lower: int = 80) -> float: """Calculate GRADE hypoglycemia for a single timeseries""" data = data.dropna() diff --git a/iglu_python/gri.py b/iglu_python/gri.py index 5a023b4..47eff50 100644 --- a/iglu_python/gri.py +++ b/iglu_python/gri.py @@ -8,7 +8,7 @@ from .utils import check_data_columns -def gri(data: Union[pd.DataFrame, pd.Series,list,np.ndarray], tz: str = "") -> pd.DataFrame|float: +def gri(data: Union[pd.DataFrame, pd.Series, list, np.ndarray], tz: str = "") -> pd.DataFrame | float: """ Calculate Glycemia Risk Index (GRI). @@ -55,7 +55,7 @@ def gri(data: Union[pd.DataFrame, pd.Series,list,np.ndarray], tz: str = "") -> p 0 35.43 """ # Handle Series input - if isinstance(data, (pd.Series, list,np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (list, np.ndarray)): data = pd.Series(data) return gri_single(data, tz) @@ -73,6 +73,7 @@ def gri(data: Union[pd.DataFrame, pd.Series,list,np.ndarray], tz: str = "") -> p return pd.DataFrame(result) + def gri_single(data: pd.Series, tz: str = "") -> float: """ Calculate Glycemia Risk Index (GRI) for a single series/subject. @@ -81,7 +82,6 @@ def gri_single(data: pd.Series, tz: str = "") -> float: if len(data) == 0: return np.nan - # Get percentages in each range below_54 = below_percent(data, targets_below=[54])["below_54"] below_70 = below_percent(data, targets_below=[70])["below_70"] @@ -89,12 +89,7 @@ def gri_single(data: pd.Series, tz: str = "") -> float: above_250 = above_percent(data, targets_above=[250])["above_250"] # Calculate GRI - gri_value = ( - 3.0 * below_54 - + 2.4 * (below_70 - below_54) - + 1.6 * above_250 - + 0.8 * (above_180 - above_250) - ) + gri_value = 3.0 * below_54 + 2.4 * (below_70 - below_54) + 1.6 * above_250 + 0.8 * (above_180 - above_250) # Threshold at 100% gri_value = min(gri_value, 100.0) diff --git a/iglu_python/gvp.py b/iglu_python/gvp.py index ce08e31..7f758aa 100644 --- a/iglu_python/gvp.py +++ b/iglu_python/gvp.py @@ -6,7 +6,7 @@ from .utils import CGMS2DayByDay, check_data_columns -def gvp(data: Union[pd.DataFrame, pd.Series]) -> pd.DataFrame|float: +def gvp(data: Union[pd.DataFrame, pd.Series]) -> pd.DataFrame | float: r""" Calculate Glucose Variability Percentage (GVP). @@ -66,9 +66,7 @@ def gvp(data: Union[pd.DataFrame, pd.Series]) -> pd.DataFrame|float: data = check_data_columns(data) data.set_index("time", inplace=True, drop=True) - out = data.groupby('id').agg( - GVP = ("gl", lambda x: gvp_single(x)) - ).reset_index() + out = data.groupby("id").agg(GVP=("gl", lambda x: gvp_single(x))).reset_index() return out @@ -119,6 +117,7 @@ def calculate_gvp(glucose_values: pd.Series, timestamps: pd.Series) -> float: return gvp + def gvp_single(subj_data): """Calculate GVP for a single subject""" # Get interpolated data diff --git a/iglu_python/hbgi.py b/iglu_python/hbgi.py index 49bc67e..4d0353c 100644 --- a/iglu_python/hbgi.py +++ b/iglu_python/hbgi.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def hbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame|float: +def hbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame | float: r""" Calculate High Blood Glucose Index (HBGI). @@ -69,11 +69,10 @@ def hbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame # Handle DataFrame input data = check_data_columns(data) - out = data.groupby('id').agg( - HBGI = ("gl", lambda x: calculate_hbgi_single(x)) - ).reset_index() + out = data.groupby("id").agg(HBGI=("gl", lambda x: calculate_hbgi_single(x))).reset_index() return out + def calculate_hbgi_single(glucose_values: pd.Series) -> float: """Helper function to calculate HBGI for a single series of values.""" glucose_values = glucose_values.dropna() diff --git a/iglu_python/hyper_index.py b/iglu_python/hyper_index.py index 8ca2302..131b7fb 100644 --- a/iglu_python/hyper_index.py +++ b/iglu_python/hyper_index.py @@ -8,7 +8,7 @@ def hyper_index( data: Union[pd.DataFrame, pd.Series, np.ndarray, list], ULTR: int = 140, a: float = 1.1, c: int = 30 -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate Hyperglycemia Index. @@ -63,7 +63,7 @@ def hyper_index( 0 0.106 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return hyper_index_single(data, ULTR, a, c) @@ -72,15 +72,12 @@ def hyper_index( data = check_data_columns(data) # Calculate hyper_index for each subject - out = data.groupby('id').agg( - hyper_index = ("gl", lambda x: hyper_index_single(x, ULTR, a, c)) - ).reset_index() + out = data.groupby("id").agg(hyper_index=("gl", lambda x: hyper_index_single(x, ULTR, a, c))).reset_index() return out -def hyper_index_single( - gl: pd.Series, ULTR: int = 140, a: float = 1.1, c: int = 30 -) -> float: + +def hyper_index_single(gl: pd.Series, ULTR: int = 140, a: float = 1.1, c: int = 30) -> float: """ Calculate Hyperglycemia Index for a single subject. """ diff --git a/iglu_python/hypo_index.py b/iglu_python/hypo_index.py index bce1dbb..d0d0109 100644 --- a/iglu_python/hypo_index.py +++ b/iglu_python/hypo_index.py @@ -8,7 +8,7 @@ def hypo_index( data: Union[pd.DataFrame, pd.Series, np.ndarray, list], LLTR: int = 80, b: float = 2, d: int = 30 -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate Hypoglycemia Index. @@ -63,20 +63,17 @@ def hypo_index( 0 0.106 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return hypo_index_single(data, LLTR, b, d) data = check_data_columns(data) - out = data.groupby('id').agg( - hypo_index = ("gl", lambda x: hypo_index_single(x, LLTR, b, d)) - ).reset_index() + out = data.groupby("id").agg(hypo_index=("gl", lambda x: hypo_index_single(x, LLTR, b, d))).reset_index() return out -def hypo_index_single( - gl: pd.Series, LLTR: int = 80, b: float = 2, d: int = 30 -) -> float: + +def hypo_index_single(gl: pd.Series, LLTR: int = 80, b: float = 2, d: int = 30) -> float: """ Calculate Hypoglycemia Index for a single subject. """ diff --git a/iglu_python/igc.py b/iglu_python/igc.py index b4200e8..cfc4ee0 100644 --- a/iglu_python/igc.py +++ b/iglu_python/igc.py @@ -16,7 +16,7 @@ def igc( b: float = 2, c: int = 30, d: int = 30, -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate Index of Glycemic Control (IGC). @@ -73,7 +73,7 @@ def igc( 0 0.106 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return igc_single(data, LLTR, ULTR, a, b, c, d) @@ -81,24 +81,17 @@ def igc( # Check and prepare data data = check_data_columns(data) - out = data.groupby('id').agg( - IGC = ("gl", lambda x: igc_single(x, LLTR, ULTR, a, b, c, d)) - ).reset_index() + out = data.groupby("id").agg(IGC=("gl", lambda x: igc_single(x, LLTR, ULTR, a, b, c, d))).reset_index() return out + def igc_single( - gl: pd.Series, - LLTR: int = 80, - ULTR: int = 140, - a: float = 1.1, - b: float = 2, - c: int = 30, - d: int = 30 + gl: pd.Series, LLTR: int = 80, ULTR: int = 140, a: float = 1.1, b: float = 2, c: int = 30, d: int = 30 ) -> float: """ Calculate Index of Glycemic Control for a single subject. """ - # Calculate hyper_index and hypo_index + # Calculate hyper_index and hypo_index out_hyper = hyper_index(gl, ULTR=ULTR, a=a, c=c) out_hypo = hypo_index(gl, LLTR=LLTR, b=b, d=d) diff --git a/iglu_python/in_range_percent.py b/iglu_python/in_range_percent.py index 76909e9..128707b 100644 --- a/iglu_python/in_range_percent.py +++ b/iglu_python/in_range_percent.py @@ -7,9 +7,9 @@ def in_range_percent( - data: Union[pd.DataFrame, pd.Series, list,np.ndarray], + data: Union[pd.DataFrame, pd.Series, list, np.ndarray], target_ranges: List[List[int]] = None, -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate percentage of values within target ranges. @@ -67,7 +67,7 @@ def in_range_percent( # Handle Series input if target_ranges is None: target_ranges = [[70, 180], [63, 140]] - if isinstance(data, (pd.Series, list,np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (list, np.ndarray)): data = pd.Series(data) return in_range_percent_single(data, target_ranges) @@ -87,9 +87,10 @@ def in_range_percent( # Convert to DataFrame df = pd.DataFrame(result) - df = df[['id'] + [col for col in df.columns if col != 'id']] + df = df[["id"] + [col for col in df.columns if col != "id"]] return df + def in_range_percent_single(data: pd.Series, target_ranges: List[List[int]] = None) -> float: """ Calculate percentage of values within target ranges for a single series/subject. @@ -99,16 +100,13 @@ def in_range_percent_single(data: pd.Series, target_ranges: List[List[int]] = No target_ranges = [[70, 180], [63, 140]] total_readings = len(data.dropna()) if total_readings == 0: - return {f"in_range_{min(range_vals)}_{max(range_vals)}": 0 - for range_vals in target_ranges} + return {f"in_range_{min(range_vals)}_{max(range_vals)}": 0 for range_vals in target_ranges} # Calculate percentages for each range percentages = {} for range_vals in target_ranges: min_val, max_val = sorted(range_vals) in_range_count = len(data[(data >= min_val) & (data <= max_val)]) - percentages[f"in_range_{min_val}_{max_val}"] = ( - in_range_count / total_readings - ) * 100 + percentages[f"in_range_{min_val}_{max_val}"] = (in_range_count / total_readings) * 100 return percentages diff --git a/iglu_python/iqr_glu.py b/iglu_python/iqr_glu.py index 4ab936b..444a311 100644 --- a/iglu_python/iqr_glu.py +++ b/iglu_python/iqr_glu.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def iqr_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame|float: +def iqr_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame | float: """ Calculate glucose level interquartile range (IQR). @@ -44,7 +44,7 @@ def iqr_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr 0 70.0 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) data = data.dropna() @@ -60,14 +60,11 @@ def iqr_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr # Calculate IQR for each subject # drop all rows with missing values data = data.dropna() - result = ( - data.groupby("id") - .agg(IQR=("gl", lambda x: iqr_glu_single(x))) - .reset_index() - ) + result = data.groupby("id").agg(IQR=("gl", lambda x: iqr_glu_single(x))).reset_index() return result + def iqr_glu_single( gl: pd.Series, ) -> float: diff --git a/iglu_python/j_index.py b/iglu_python/j_index.py index 417c029..9723af1 100644 --- a/iglu_python/j_index.py +++ b/iglu_python/j_index.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def j_index(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame|float: +def j_index(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame | float: """ Calculate J-Index score for glucose measurements. @@ -52,7 +52,7 @@ def j_index(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr 0 1.5000 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return j_index_single(data) @@ -60,12 +60,11 @@ def j_index(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr # Handle DataFrame input data = check_data_columns(data) - out = data.groupby('id').agg( - J_index = ("gl", lambda x: j_index_single(x)) - ).reset_index() + out = data.groupby("id").agg(J_index=("gl", lambda x: j_index_single(x))).reset_index() return out -def j_index_single(gl: pd.Series) -> float: + +def j_index_single(gl: pd.Series) -> float: """ Calculate J-Index score for a single subject. """ diff --git a/iglu_python/lbgi.py b/iglu_python/lbgi.py index 54807ab..369f306 100644 --- a/iglu_python/lbgi.py +++ b/iglu_python/lbgi.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def lbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame|float: +def lbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame | float: r""" Calculate the Low Blood Glucose Index (LBGI) for each subject. @@ -64,7 +64,7 @@ def lbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame LBGI 0 0.123456 """ - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return calculate_lbgi(data) @@ -72,11 +72,10 @@ def lbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame # Check DataFrame format check_data_columns(data) - out = data.groupby('id').agg( - LBGI = ("gl", lambda x: calculate_lbgi(x)) - ).reset_index() + out = data.groupby("id").agg(LBGI=("gl", lambda x: calculate_lbgi(x))).reset_index() return out + def calculate_lbgi(glucose_values: pd.Series) -> float: """ Calculate LBGI for a single series of glucose values. @@ -110,4 +109,3 @@ def calculate_lbgi(glucose_values: pd.Series) -> float: lbgi = 10 * np.sum(fbg[glucose_values < 112.5] ** 2) / n return lbgi - diff --git a/iglu_python/m_value.py b/iglu_python/m_value.py index 9048acf..89ef5e1 100644 --- a/iglu_python/m_value.py +++ b/iglu_python/m_value.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def m_value(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], r: float = 90) -> pd.DataFrame|float: +def m_value(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], r: float = 90) -> pd.DataFrame | float: r""" Calculate the M-value of Schlichtkrull et al. (1965) for each subject. @@ -60,7 +60,7 @@ def m_value(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], r: float = 9 0 111.11 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return m_value_single(data, r) @@ -68,12 +68,11 @@ def m_value(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], r: float = 9 # Handle DataFrame input data = check_data_columns(data) - out = data.groupby('id').agg( - M_value = ("gl", lambda x: m_value_single(x, r)) - ).reset_index() + out = data.groupby("id").agg(M_value=("gl", lambda x: m_value_single(x, r))).reset_index() return out -def m_value_single(gl: pd.Series, r: float = 90) -> float: + +def m_value_single(gl: pd.Series, r: float = 90) -> float: """ Calculate the M-value of Schlichtkrull et al. (1965) for a single subject. """ @@ -82,4 +81,3 @@ def m_value_single(gl: pd.Series, r: float = 90) -> float: return np.nan m_value = 1000 * np.mean(np.abs(np.log10(gl / r)) ** 3) return m_value - diff --git a/iglu_python/mad_glu.py b/iglu_python/mad_glu.py index 5d13881..eb97735 100644 --- a/iglu_python/mad_glu.py +++ b/iglu_python/mad_glu.py @@ -6,9 +6,7 @@ from .utils import check_data_columns -def mad_glu( - data: Union[pd.DataFrame, pd.Series, np.ndarray, list], constant: float = 1.4826 -) -> pd.DataFrame|float: +def mad_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], constant: float = 1.4826) -> pd.DataFrame | float: """ Calculate Median Absolute Deviation (MAD) of glucose values. @@ -53,7 +51,7 @@ def mad_glu( 0 27.5 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return mad_glu_single(data, constant) @@ -61,11 +59,10 @@ def mad_glu( # Handle DataFrame input data = check_data_columns(data) - out = data.groupby('id').agg( - MAD = ("gl", lambda x: mad_glu_single(x, constant)) - ).reset_index() + out = data.groupby("id").agg(MAD=("gl", lambda x: mad_glu_single(x, constant))).reset_index() return out + def mad_glu_single(gl: pd.Series, constant: float = 1.4826) -> float: """ Calculate Median Absolute Deviation (MAD) of glucose values for a single subject. diff --git a/iglu_python/mag.py b/iglu_python/mag.py index faddd1d..faee060 100644 --- a/iglu_python/mag.py +++ b/iglu_python/mag.py @@ -12,7 +12,7 @@ def mag( dt0: Optional[int] = None, inter_gap: int = 45, tz: str = "", -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate Mean Absolute Glucose (MAG). @@ -79,13 +79,12 @@ def mag( # Handle DataFrame input data = check_data_columns(data) - data.set_index('time', drop=True, inplace=True) + data.set_index("time", drop=True, inplace=True) - out = data.groupby('id').agg( - MAG = ("gl", lambda x: mag_single(x, n, dt0, inter_gap, tz)) - ).reset_index() + out = data.groupby("id").agg(MAG=("gl", lambda x: mag_single(x, n, dt0, inter_gap, tz))).reset_index() return out + def mag_single(gl: pd.Series, n: int = 60, dt0: Optional[int] = None, inter_gap: int = 45, tz: str = "") -> float: """Calculate MAG for a single subject""" # Convert data to day-by-day format @@ -110,7 +109,7 @@ def mag_single(gl: pd.Series, n: int = 60, dt0: Optional[int] = None, inter_gap: lag = readings_per_interval if is_iglu_r_compatible(): - idx = np.arange(0,len(gl_values),lag) + idx = np.arange(0, len(gl_values), lag) gl_values_idx = gl_values[idx] diffs = gl_values_idx[1:] - gl_values_idx[:-1] diffs = np.abs(diffs) diff --git a/iglu_python/mage.py b/iglu_python/mage.py index f97fa54..f5ca657 100644 --- a/iglu_python/mage.py +++ b/iglu_python/mage.py @@ -124,13 +124,11 @@ def mage( } ) if version == "ma": - mage_val = mage_ma_single(data_df, short_ma, long_ma, direction, - return_type='num', - inter_gap=inter_gap, - max_gap=max_gap, - tz=tz) + mage_val = mage_ma_single( + data_df, short_ma, long_ma, direction, return_type="num", inter_gap=inter_gap, max_gap=max_gap, tz=tz + ) else: - mage_val = mage_naive(data_df,sd_multiplier=sd_multiplier) + mage_val = mage_naive(data_df, sd_multiplier=sd_multiplier) return mage_val # Handle DataFrame input @@ -144,20 +142,21 @@ def mage( continue if version == "ma": - mage_val = mage_ma_single(subject_data, short_ma, long_ma, direction, return_type,inter_gap,max_gap,tz) - if return_type == "df" : + mage_val = mage_ma_single(subject_data, short_ma, long_ma, direction, return_type, inter_gap, max_gap, tz) + if return_type == "df": subject_result_dict = mage_val.to_dict() else: subject_result_dict = {"MAGE": mage_val} else: - mage_val = mage_naive(subject_data,sd_multiplier=sd_multiplier) + mage_val = mage_naive(subject_data, sd_multiplier=sd_multiplier) subject_result_dict = {"MAGE": mage_val} result.append({"id": subject, **subject_result_dict}) return pd.DataFrame(result) -def mage_naive(data: pd.DataFrame,sd_multiplier:float = 1.0) -> float: + +def mage_naive(data: pd.DataFrame, sd_multiplier: float = 1.0) -> float: """Calculate MAGE using naive algorithm""" # Calculate absolute differences from mean mean_gl = data["gl"].mean() @@ -171,308 +170,302 @@ def mage_naive(data: pd.DataFrame,sd_multiplier:float = 1.0) -> float: return float(mage_val) if not pd.isna(mage_val) else np.nan -def mage_ma_single(data: pd.DataFrame, short_ma: int, long_ma: int, - direction:str ='avg', - return_type:str = "num", - inter_gap:int = 45, - max_gap:int = 180, - tz:str = "" ) -> pd.DataFrame|float: - """Calculate MAGE using moving average algorithm for a single subject""" - ## 1. Preprocessing - # 1.1 Interpolate over uniform grid - # Note: always interpolate to 5 minute grid + +def _preprocess_data(data: pd.DataFrame, short_ma: int, long_ma: int, inter_gap: int, tz: str) -> pd.DataFrame: + """Preprocess data for MAGE calculation""" + # Interpolate over uniform grid data_ip = CGMS2DayByDay(data, dt0=5, inter_gap=inter_gap, tz=tz) - data_ip[2] # Time between measurements in minutes - # replace for 5 min to fix bug in CGMS2DayByDay day_one = data_ip[1][0] - len(data_ip[1]) - - # 1.2 Generate grid times by starting from day one and cumulatively summing - # note fix 5 min used in interpretation gl = data_ip[0].flatten().tolist() - time_ip = [pd.Timedelta(i * 5, unit="m") + day_one for i in range(1,len(gl)+1)] + time_ip = [pd.Timedelta(i * 5, unit="m") + day_one for i in range(1, len(gl) + 1)] - # 1.3 Recalculate short_ma and long_ma because short and long are based on 5 minutes originally - # > Multiply by 5 to get length in min - # > Divide by dt0 to get rounded number of measurements that are roughly equal to original short/long ma definition - # short_ma = round(short_ma*5/dt0) - # long_ma = round(long_ma*5/dt0) # Ensure short_ma and long_ma are appropriate if short_ma >= long_ma: short_ma, long_ma = long_ma, short_ma - ## 2. Change to interpolated data (times and glucose) - # > change data into id, interpolated times, interpolated glucose (t to get rowwise) - # > drop NA rows before first glucose reading - # > then drop NA rows after last glucose reading - # > Label NA glucose as gap (gap = 1) - interpolated_data = pd.DataFrame({ - "id" : data['id'].iloc[0], - "time": pd.Series(time_ip, dtype='datetime64[ns]'), - "gl": pd.Series(gl, dtype='float64') - }) + # Create interpolated data + interpolated_data = pd.DataFrame( + { + "id": data["id"].iloc[0], + "time": pd.Series(time_ip, dtype="datetime64[ns]"), + "gl": pd.Series(gl, dtype="float64"), + } + ) + # Drop NA rows before first glucose reading - first_valid_idx = interpolated_data['gl'].first_valid_index() + first_valid_idx = interpolated_data["gl"].first_valid_index() if first_valid_idx is not None: interpolated_data = interpolated_data.iloc[first_valid_idx:] + # Drop NA rows after last glucose reading - last_valid_idx = interpolated_data['gl'].last_valid_index() + last_valid_idx = interpolated_data["gl"].last_valid_index() if last_valid_idx is not None: - interpolated_data = interpolated_data.iloc[:last_valid_idx+1] + interpolated_data = interpolated_data.iloc[: last_valid_idx + 1] + # Add gap column to mark NA values as 1 - interpolated_data['gap'] = interpolated_data['gl'].isna().astype(int) + interpolated_data["gap"] = interpolated_data["gl"].isna().astype(int) + + return interpolated_data + + +def _filter_mage_results(return_val: pd.DataFrame, direction: str) -> pd.DataFrame: + """Filter MAGE results based on direction""" + if direction == "plus": + return return_val[return_val["plus_or_minus"] == "PLUS"].copy() + elif direction == "minus": + return return_val[return_val["plus_or_minus"] == "MINUS"].copy() + elif direction == "avg": + return return_val[return_val["MAGE"].notna()].copy() + elif direction == "max": + # Group by start,end and keep max mage in each group + idx = return_val.groupby(["start", "end"])["MAGE"].idxmax() + return return_val.loc[idx].reset_index(drop=True) + else: # default: first excursions only + return return_val[return_val["first_excursion"]].copy() + + +def _calculate_weighted_mage(res: pd.DataFrame) -> float: + """Calculate time-weighted MAGE""" + if res.empty: + return np.nan - # 4. Time Series Segmentation: split gaps > max_gap into separate segments - dfs = segment_time_series(interpolated_data,max_gap) # note: max_gap is in minutes + res["hours"] = res["end"] - res["start"] + res["weight"] = res["hours"] / res["hours"].sum() + return (res["MAGE"] * res["weight"]).sum() - # 5. Calculate MAGE on each identified segment + +def mage_ma_single( + data: pd.DataFrame, + short_ma: int, + long_ma: int, + direction: str = "avg", + return_type: str = "num", + inter_gap: int = 45, + max_gap: int = 180, + tz: str = "", +) -> pd.DataFrame | float: + """Calculate MAGE using moving average algorithm for a single subject""" + + # Preprocess data + interpolated_data = _preprocess_data(data, short_ma, long_ma, inter_gap, tz) + + # Time Series Segmentation: split gaps > max_gap into separate segments + dfs = segment_time_series(interpolated_data, max_gap) + + # Calculate MAGE on each identified segment return_val = pd.DataFrame(columns=["start", "end", "mage", "plus_or_minus", "first_excursion"]) for segment in dfs: - ret = mage_atomic(segment,short_ma,long_ma) + ret = mage_atomic(segment, short_ma, long_ma) if return_val.empty: return_val = ret else: return_val = pd.concat([return_val, ret], ignore_index=True) - if return_type == 'df': + if return_type == "df": return return_val - """Process MAGE results with filtering and weighting.""" - # Filter by direction (equivalent to the previous R filtering code) - if direction == 'plus': - res = return_val[return_val['plus_or_minus'] == 'PLUS'].copy() - elif direction == 'minus': - res = return_val[return_val['plus_or_minus'] == 'MINUS'].copy() - elif direction == 'avg': - res = return_val[return_val['MAGE'].notna()].copy() - elif direction == 'max': - # Group by start,end and keep max mage in each group - idx = return_val.groupby(['start', 'end'])['MAGE'].idxmax() - res = return_val.loc[idx].reset_index(drop=True) - else: # default: first excursions only - res = return_val[return_val['first_excursion']].copy() - - # Calculate time-weighted MAGE - if res.empty: - return np.nan + # Filter results based on direction + res = _filter_mage_results(return_val, direction) - res['hours'] = res['end'] - res['start'] - res['weight'] = res['hours'] / res['hours'].sum() - weighted_mage = (res['MAGE'] * res['weight']).sum() + # Calculate weighted MAGE + return _calculate_weighted_mage(res) - return weighted_mage -def mage_atomic(data, short_ma,long_ma): - """ 0. Calculates MAGE on 1 segment of CGM trace """ - - # 2c. Calculate the moving average values +def _calculate_moving_averages(data: pd.DataFrame, short_ma: int, long_ma: int) -> pd.DataFrame: + """Calculate short and long moving averages""" data = data.copy() data["MA_Short"] = data["gl"].rolling(window=short_ma, min_periods=1).mean() data["MA_Long"] = data["gl"].rolling(window=long_ma, min_periods=1).mean() + # Fill leading NAs (forward fill first valid value) if short_ma > len(data): - data.loc[data.index[:short_ma], 'MA_Short'] = data['MA_Short'].iloc[-1] + data.loc[data.index[:short_ma], "MA_Short"] = data["MA_Short"].iloc[-1] else: - data.loc[data.index[:short_ma], 'MA_Short'] = data['MA_Short'].iloc[short_ma-1] + data.loc[data.index[:short_ma], "MA_Short"] = data["MA_Short"].iloc[short_ma - 1] + if long_ma > len(data): - data.loc[data.index[:long_ma], 'MA_Long'] = data['MA_Long'].iloc[-1] + data.loc[data.index[:long_ma], "MA_Long"] = data["MA_Long"].iloc[-1] else: - data.loc[data.index[:long_ma], 'MA_Long'] = data['MA_Long'].iloc[long_ma-1] + data.loc[data.index[:long_ma], "MA_Long"] = data["MA_Long"].iloc[long_ma - 1] + # Calculate difference - data['DELTA_SHORT_LONG'] = data['MA_Short'] - data['MA_Long'] - data = data.reset_index(drop=True) + data["DELTA_SHORT_LONG"] = data["MA_Short"] - data["MA_Long"] + return data.reset_index(drop=True) + + +def _check_data_validity(data: pd.DataFrame, short_ma: int) -> bool: + """Check if data is valid for MAGE calculation""" nmeasurements = len(data) + return not ( + data["gl"].isnull().all() or nmeasurements < 7 or nmeasurements < short_ma or np.std(data["gl"], ddof=1) < 1 + ) - # Sanity check - if ( - data['gl'].isnull().all() or - nmeasurements < 7 or - nmeasurements < short_ma or - np.std(data['gl'], ddof=1) < 1 - ): - return pd.DataFrame({ - 'start': [data['time'].iloc[0]], - 'end': [data['time'].iloc[-1]], - 'MAGE': [np.nan], - 'plus_or_minus': [np.nan], - 'first_excursion': [np.nan] - }) - - # 2d. Create a preallocated list of crossing point ids & type - # Find crossing points - # Detect trend reversal points in glucose data using DELTA signal. - # Initialize variables - idx = list(data.index) # R: idx = as.numeric(rownames(.data)) - types = {'REL_MIN': 0, 'REL_MAX': 1} # R: types = list2env(list(REL_MIN=0, REL_MAX=1)) - - # Create storage lists - R: list_cross <- list("id" = rep.int(NA, nmeasurements), - # "type" = rep.int(NA, nmeasurements)) - list_cross = { - 'id': [np.nan] * nmeasurements, - 'type': [np.nan] * nmeasurements - } + +def _find_crossing_points(data: pd.DataFrame) -> tuple[list, list]: + """Find crossing points in the data""" + idx = list(data.index) + types = {"REL_MIN": 0, "REL_MAX": 1} + nmeasurements = len(data) + + # Create storage lists + list_cross = {"id": [np.nan] * nmeasurements, "type": [np.nan] * nmeasurements} # Always add 1st point - list_cross['id'][0] = idx[0] - list_cross['type'][0] = types['REL_MAX'] if data['DELTA_SHORT_LONG'].iloc[0] > 0 else types['REL_MIN'] - count = 1 # Python uses 0-based indexing, so count starts at 1 + list_cross["id"][0] = idx[0] + list_cross["type"][0] = types["REL_MAX"] if data["DELTA_SHORT_LONG"].iloc[0] > 0 else types["REL_MIN"] + count = 1 - # treat DELTA_SHORT_LONG==0 as NaN ( so we can skip its multiplication) - data.loc[data['DELTA_SHORT_LONG'] == 0, 'DELTA_SHORT_LONG'] = np.nan + # treat DELTA_SHORT_LONG==0 as NaN + data.loc[data["DELTA_SHORT_LONG"] == 0, "DELTA_SHORT_LONG"] = np.nan - # Main loop - R: for(i in 2:length(.data$DELTA_SHORT_LONG)) - for i in range(1, len(data['DELTA_SHORT_LONG'])): + # Main loop + for i in range(1, len(data["DELTA_SHORT_LONG"])): # Check data validity - if (not pd.isna(data['gl'].iloc[i]) and - not pd.isna(data['gl'].iloc[i-1]) and - not pd.isna(data['DELTA_SHORT_LONG'].iloc[i]) and - not pd.isna(data['DELTA_SHORT_LONG'].iloc[i-1])): - - # Primary crossover detection: crossing point if DELTA changes sign - if (data['DELTA_SHORT_LONG'].iloc[i] * data['DELTA_SHORT_LONG'].iloc[i-1] < 0): - list_cross['id'][count] = idx[i] - if data['DELTA_SHORT_LONG'].iloc[i] < data['DELTA_SHORT_LONG'].iloc[i-1]: - list_cross['type'][count] = types['REL_MIN'] + if ( + not pd.isna(data["gl"].iloc[i]) + and not pd.isna(data["gl"].iloc[i - 1]) + and not pd.isna(data["DELTA_SHORT_LONG"].iloc[i]) + and not pd.isna(data["DELTA_SHORT_LONG"].iloc[i - 1]) + ): + # Primary crossover detection + if data["DELTA_SHORT_LONG"].iloc[i] * data["DELTA_SHORT_LONG"].iloc[i - 1] < 0: + list_cross["id"][count] = idx[i] + if data["DELTA_SHORT_LONG"].iloc[i] < data["DELTA_SHORT_LONG"].iloc[i - 1]: + list_cross["type"][count] = types["REL_MIN"] else: - list_cross['type'][count] = types['REL_MAX'] + list_cross["type"][count] = types["REL_MAX"] count += 1 - # Gap handling: needed for gaps, where DELTA_SHORT_LONG(i-1 | i-2) = NaN - elif (not pd.isna(data['DELTA_SHORT_LONG'].iloc[i]) and - count >= 1): # Make sure we have a previous crossover - - # R: match(list_cross$id[count-1], idx) - find index of previous crossover + # Gap handling + elif not pd.isna(data["DELTA_SHORT_LONG"].iloc[i]) and count >= 1: try: - prev_cross_idx = idx.index(list_cross['id'][count-1]) - prev_delta = data['DELTA_SHORT_LONG'].iloc[prev_cross_idx] + prev_cross_idx = idx.index(list_cross["id"][count - 1]) + prev_delta = data["DELTA_SHORT_LONG"].iloc[prev_cross_idx] - if (data['DELTA_SHORT_LONG'].iloc[i] * prev_delta < 0): - list_cross['id'][count] = idx[i] - if data['DELTA_SHORT_LONG'].iloc[i] < prev_delta: - list_cross['type'][count] = types['REL_MIN'] + if data["DELTA_SHORT_LONG"].iloc[i] * prev_delta < 0: + list_cross["id"][count] = idx[i] + if data["DELTA_SHORT_LONG"].iloc[i] < prev_delta: + list_cross["type"][count] = types["REL_MIN"] else: - list_cross['type'][count] = types['REL_MAX'] + list_cross["type"][count] = types["REL_MAX"] count += 1 except ValueError: - # Handle case where previous crossover id not found in idx pass - # Add last point to capture excursion at end - # R: utils::tail(idx, 1) + # Add last point last_idx = idx[-1] - list_cross['id'][count] = last_idx + list_cross["id"][count] = last_idx + list_cross["type"][count] = types["REL_MAX"] if data["DELTA_SHORT_LONG"].iloc[-1] > 0 else types["REL_MIN"] - if data['DELTA_SHORT_LONG'].iloc[-1] > 0: - list_cross['type'][count] = types['REL_MAX'] - else: - list_cross['type'][count] = types['REL_MIN'] + # Filter out NaN values + clean_ids = [x for x in list_cross["id"] if not pd.isna(x)] + clean_types = [x for x in list_cross["type"] if not pd.isna(x)] - # Filter out NaN values - R: list_cross$id[!is.na(list_cross$id)] - clean_ids = [x for x in list_cross['id'] if not pd.isna(x)] - clean_types = [x for x in list_cross['type'] if not pd.isna(x)] + return clean_ids, clean_types - # Create DataFrame - R: do.call(cbind.data.frame, list_cross) - crosses = pd.DataFrame({ - "id":clean_ids, - "type":clean_types - }) - # 2e. Calculate min and max glucose values from ids and types in crosses + store indexes for plotting later - # R: num_extrema = nrow(crosses)-1 +def _calculate_extrema(data: pd.DataFrame, crosses: pd.DataFrame) -> tuple[list, list]: + """Calculate min and max glucose values from crossing points""" num_extrema = len(crosses) - 1 - - # R: minmax <- rep(NA_real_, num_extrema), indexes <- rep(NA_real_, num_extrema) minmax = [np.nan] * num_extrema indexes = [np.nan] * num_extrema + types = {"REL_MIN": 0, "REL_MAX": 1} - # R: for(i in 1:num_extrema) for i in range(num_extrema): # Define search boundaries - # R: s1 <- ifelse(i == 1, crosses[i, 1], indexes[i-1]) - if i == 0: # First extrema - s1 = int(crosses.iloc[i]['id']) # crosses[i, 1] in R (1-indexed) + if i == 0: + s1 = int(crosses.iloc[i]["id"]) else: - s1 = int(indexes[i-1]) # last minmax index + s1 = int(indexes[i - 1]) - # R: s2 <- crosses[i+1,1] - s2 = int(crosses.iloc[i+1]['id']) # crosses[i+1, 1] in R + s2 = int(crosses.iloc[i + 1]["id"]) - # Extract glucose segment - R: .data[as.character(s1:s2), ]$gl - segment_start = s1 - segment_end = s2 - glucose_segment = data['gl'].iloc[segment_start:segment_end+1] # including next cross point + # Extract glucose segment + glucose_segment = data["gl"].iloc[s1 : s2 + 1] # Find min or max based on crossover type - if crosses.iloc[i]['type'] == types['REL_MIN']: # crosses[i, "type"] in R - # R: min(.data[as.character(s1:s2), ]$gl, na.rm = TRUE) + if crosses.iloc[i]["type"] == types["REL_MIN"]: minmax[i] = glucose_segment.min() - # R: which.min(.data[as.character(s1:s2), ]$gl)+s1-1 indexes[i] = glucose_segment.idxmin() else: - # R: max(.data[as.character(s1:s2), ]$gl, na.rm = TRUE) minmax[i] = glucose_segment.max() - # R: which.max(.data[as.character(s1:s2), ]$gl)+s1-1 indexes[i] = glucose_segment.idxmax() - # excursion elimination - differences = np.subtract.outer(minmax, minmax).T - standardD = data['gl'].std() # pandas uses sample std dev by default - len(minmax) + return minmax, indexes - # MAGE+ algorithm, which identifies and measures positive glycemic excursions - # (nadir-to-peak movements that exceed the standard deviation threshold). - mage_plus_heights, mage_plus_tp_pairs = calculate_mage_plus(differences, minmax, standardD) +def mage_atomic(data, short_ma, long_ma): + """Calculate MAGE on 1 segment of CGM trace""" + + # Calculate moving averages + data = _calculate_moving_averages(data, short_ma, long_ma) + + # Sanity check + if not _check_data_validity(data, short_ma): + return pd.DataFrame( + { + "start": [data["time"].iloc[0]], + "end": [data["time"].iloc[-1]], + "MAGE": [np.nan], + "plus_or_minus": [np.nan], + "first_excursion": [np.nan], + } + ) + + # Find crossing points + clean_ids, clean_types = _find_crossing_points(data) + crosses = pd.DataFrame({"id": clean_ids, "type": clean_types}) + + # Calculate extrema + minmax, indexes = _calculate_extrema(data, crosses) - # MAGE- algorithm, which identifies and measures negative glycemic excursions - # (peak-to-nadir movements that exceed the standard deviation threshold). + # Calculate differences and standard deviation + differences = np.subtract.outer(minmax, minmax).T + standardD = data["gl"].std() + + # Calculate MAGE+ and MAGE- + mage_plus_heights, mage_plus_tp_pairs = calculate_mage_plus(differences, minmax, standardD) mage_minus_heights, mage_minus_tp_pairs = calculate_mage_minus(differences, minmax, standardD) if len(mage_minus_heights) == 0 and len(mage_plus_heights) == 0: - return pd.DataFrame({ - 'start': [data['time'].iloc[0]], - 'end': [data['time'].iloc[-1]], - 'MAGE': [np.nan], - 'plus_or_minus': [np.nan], - 'first_excursion': [np.nan] - }, index=[0]) + return pd.DataFrame( + { + "start": [data["time"].iloc[0]], + "end": [data["time"].iloc[-1]], + "MAGE": [np.nan], + "plus_or_minus": [np.nan], + "first_excursion": [np.nan], + }, + index=[0], + ) # Determine which excursion type occurs first - if (len(mage_plus_heights) > 0 and - (len(mage_minus_heights) == 0 or - mage_plus_tp_pairs[0][1] <= mage_minus_tp_pairs[0][0])): - is_plus_first = True - else: - is_plus_first = False - - # Create MAGE+ result dataframe - mage_plus = pd.DataFrame({ - 'start': [data['time'].iloc[0]], - 'end': [data['time'].iloc[-1]], - 'MAGE': [np.mean(mage_plus_heights) if len(mage_plus_heights) > 0 else np.nan], - 'plus_or_minus': ['PLUS'], - 'first_excursion': [is_plus_first] - }) - - # Create MAGE- result dataframe - mage_minus = pd.DataFrame({ - 'start': [data['time'].iloc[0]], - 'end': [data['time'].iloc[-1]], - 'MAGE': [abs(np.mean(mage_minus_heights)) if len(mage_minus_heights) > 0 else np.nan], - 'plus_or_minus': ['MINUS'], - 'first_excursion': [not is_plus_first] - }) - - # Determine which direction has maximum MAGE value - ((mage_plus['MAGE'].iloc[0] >= mage_minus['MAGE'].iloc[0]) - if not pd.isna(mage_plus['MAGE'].iloc[0]) - and not pd.isna(mage_minus['MAGE'].iloc[0]) - else False + is_plus_first = len(mage_plus_heights) > 0 and ( + len(mage_minus_heights) == 0 or mage_plus_tp_pairs[0][1] <= mage_minus_tp_pairs[0][0] ) - return pd.concat([mage_plus, mage_minus], ignore_index=True) + # Create result dataframes + mage_plus = pd.DataFrame( + { + "start": [data["time"].iloc[0]], + "end": [data["time"].iloc[-1]], + "MAGE": [np.mean(mage_plus_heights) if len(mage_plus_heights) > 0 else np.nan], + "plus_or_minus": ["PLUS"], + "first_excursion": [is_plus_first], + } + ) + mage_minus = pd.DataFrame( + { + "start": [data["time"].iloc[0]], + "end": [data["time"].iloc[-1]], + "MAGE": [abs(np.mean(mage_minus_heights)) if len(mage_minus_heights) > 0 else np.nan], + "plus_or_minus": ["MINUS"], + "first_excursion": [not is_plus_first], + } + ) + return pd.concat([mage_plus, mage_minus], ignore_index=True) def calculate_mage_plus(differences, minmax, standardD): @@ -494,7 +487,7 @@ def calculate_mage_plus(differences, minmax, standardD): while j < N: # Get differences from previous extrema to current point j - delta = differences[prev_j:j+1, j] # j+1 because Python slicing is exclusive + delta = differences[prev_j : j + 1, j] # j+1 because Python slicing is exclusive if len(delta) == 0: j += 1 @@ -526,6 +519,7 @@ def calculate_mage_plus(differences, minmax, standardD): return mage_plus_heights, mage_plus_tp_pairs + def calculate_mage_minus(differences, minmax, standardD): """ Calculate MAGE- (negative glycemic excursions) @@ -545,7 +539,7 @@ def calculate_mage_minus(differences, minmax, standardD): while j < N: # Get differences from previous extrema to current point j - delta = differences[prev_j:j+1, j] # j+1 because Python slicing is exclusive + delta = differences[prev_j : j + 1, j] # j+1 because Python slicing is exclusive if len(delta) == 0: j += 1 @@ -576,6 +570,7 @@ def calculate_mage_minus(differences, minmax, standardD): return mage_minus_heights, mage_minus_tp_pairs + def segment_time_series(data, max_gap_minutes): """ Split glucose time series into segments based on large gaps @@ -584,30 +579,30 @@ def segment_time_series(data, max_gap_minutes): # Calculate time differences # Calculate time differences between consecutive non-NA glucose readings - data['time_diff'] = np.nan - valid_indices = data['gl'].notna() + data["time_diff"] = np.nan + valid_indices = data["gl"].notna() if valid_indices.any(): # Get timestamps of valid readings - valid_times = data.loc[valid_indices, 'time'] + valid_times = data.loc[valid_indices, "time"] # Calculate differences between consecutive valid readings time_diffs = valid_times.diff().dt.total_seconds() / 60 # Convert to minutes # Assign differences back to original dataframe at valid indices - data.loc[valid_indices, 'time_diff'] = time_diffs + data.loc[valid_indices, "time_diff"] = time_diffs # Identify where gaps exceed threshold - large_gaps = data['time_diff'] > max_gap_minutes + large_gaps = data["time_diff"] > max_gap_minutes # Create segment labels by cumulatively summing large gaps # This creates a new segment ID each time we encounter a large gap - data['segment_id'] = large_gaps.cumsum() + data["segment_id"] = large_gaps.cumsum() # Group by segment and return list of DataFrames segments = [] - for _segment_id, group in data.groupby('segment_id'): + for _segment_id, group in data.groupby("segment_id"): # Drop the temporary columns we added - group = group.drop(['time_diff', 'segment_id'], axis=1) + group = group.drop(["time_diff", "segment_id"], axis=1) # Drop rows with NA glucose values at the end of the segment - while len(group) > 0 and pd.isna(group['gl'].iloc[-1]): + while len(group) > 0 and pd.isna(group["gl"].iloc[-1]): group = group.iloc[:-1] segments.append(group.reset_index(drop=True)) diff --git a/iglu_python/mean_glu.py b/iglu_python/mean_glu.py index 4757ccb..f2c5e23 100644 --- a/iglu_python/mean_glu.py +++ b/iglu_python/mean_glu.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def mean_glu(data: Union[pd.DataFrame, list, np.ndarray, pd.Series]) -> pd.DataFrame|float: +def mean_glu(data: Union[pd.DataFrame, list, np.ndarray, pd.Series]) -> pd.DataFrame | float: """ Calculate mean glucose value for each subject. @@ -46,7 +46,7 @@ def mean_glu(data: Union[pd.DataFrame, list, np.ndarray, pd.Series]) -> pd.DataF """ # Handle Series input if isinstance(data, (list, np.ndarray, pd.Series)): - if isinstance(data, (list,np.ndarray)): + if isinstance(data, (list, np.ndarray)): data = pd.Series(data) return data.mean() diff --git a/iglu_python/median_glu.py b/iglu_python/median_glu.py index b2ca9da..62224c1 100644 --- a/iglu_python/median_glu.py +++ b/iglu_python/median_glu.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def median_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame|float: +def median_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame | float: """ Calculate median glucose value for each subject. @@ -45,7 +45,7 @@ def median_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.Dat 0 160.0 """ # Handle Series input - if isinstance(data, (pd.Series,list, np.ndarray)): + if isinstance(data, (pd.Series, list, np.ndarray)): if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return data.median() diff --git a/iglu_python/modd.py b/iglu_python/modd.py index a8bba91..4c2479e 100644 --- a/iglu_python/modd.py +++ b/iglu_python/modd.py @@ -6,9 +6,7 @@ from .utils import CGMS2DayByDay, check_data_columns -def modd( - data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lag: int = 1, tz: str = "" -) -> pd.DataFrame|float: +def modd(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lag: int = 1, tz: str = "") -> pd.DataFrame | float: """ Calculate Mean of Daily Differences (MODD). @@ -67,12 +65,11 @@ def modd( # Handle DataFrame input data = check_data_columns(data) - data.set_index('time', drop=True, inplace=True) - out = data.groupby('id').agg( - MODD = ("gl", lambda x: modd_single(x, lag, tz)) - ).reset_index() + data.set_index("time", drop=True, inplace=True) + out = data.groupby("id").agg(MODD=("gl", lambda x: modd_single(x, lag, tz))).reset_index() return out + def modd_single(data: pd.Series, lag: int = 1, tz: str = "") -> float: """Calculate MODD for a single subject""" # Convert data to day-by-day format diff --git a/iglu_python/pgs.py b/iglu_python/pgs.py index 763203f..dfb751f 100644 --- a/iglu_python/pgs.py +++ b/iglu_python/pgs.py @@ -10,9 +10,7 @@ from .utils import check_data_columns -def pgs( - data: Union[pd.DataFrame, pd.Series], dur_length: int = 20, end_length: int = 30 -) -> pd.DataFrame|float: +def pgs(data: Union[pd.DataFrame, pd.Series], dur_length: int = 20, end_length: int = 30) -> pd.DataFrame | float: """ Calculate Personal Glycemic State (PGS). @@ -87,19 +85,18 @@ def pgs( # Handle DataFrame input data = check_data_columns(data) - data.set_index('time', drop=True, inplace=True) + data.set_index("time", drop=True, inplace=True) - out = data.groupby('id').agg( - PGS = ("gl", lambda x: pgs_single(x, dur_length, end_length)) - ).reset_index() + out = data.groupby("id").agg(PGS=("gl", lambda x: pgs_single(x, dur_length, end_length))).reset_index() return out + def pgs_single(gl: pd.Series, dur_length: int = 20, end_length: int = 30) -> float: """Calculate PGS for a single subject""" # Calculate components gvp_val = gvp(gl) mean_val = mean_glu(gl) - ptir_val = in_range_percent(gl, target_ranges=[[70, 180]])['in_range_70_180'] + ptir_val = in_range_percent(gl, target_ranges=[[70, 180]])["in_range_70_180"] # Calculate episode components eps = episode_calculation( @@ -116,8 +113,7 @@ def pgs_single(gl: pd.Series, dur_length: int = 20, end_length: int = 30) -> flo f_gvp = 1 + (9 / (1 + np.exp(-0.049 * (gvp_val - 65.47)))) f_ptir = 1 + (9 / (1 + np.exp(0.0833 * (ptir_val - 55.04)))) f_mg = 1 + 9 * ( - (1 / (1 + np.exp(0.1139 * (mean_val - 72.08)))) - + (1 / (1 + np.exp(-0.09195 * (mean_val - 157.57)))) + (1 / (1 + np.exp(0.1139 * (mean_val - 72.08)))) + (1 / (1 + np.exp(-0.09195 * (mean_val - 157.57)))) ) f_h54 = 0.5 + 4.5 * (1 - np.exp(-0.91093 * n54)) @@ -127,4 +123,3 @@ def pgs_single(gl: pd.Series, dur_length: int = 20, end_length: int = 30) -> flo pgs_score = f_gvp + f_ptir + f_mg + f_h54 + f_h70 return pgs_score - diff --git a/iglu_python/process_data.py b/iglu_python/process_data.py index d5ef53b..0959362 100644 --- a/iglu_python/process_data.py +++ b/iglu_python/process_data.py @@ -7,12 +7,144 @@ from .utils import localize_naive_timestamp +def _validate_input_data(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> None: + """Validate input data type""" + if not isinstance(data, (pd.DataFrame, pd.Series, list, np.ndarray)): + raise TypeError("Invalid data type, please use DataFrame, Series, list, or numpy array.") + + +def _convert_to_dataframe( + data: Union[pd.DataFrame, pd.Series, list, np.ndarray], + glu: Optional[str], + timestamp: Optional[str], + id: Optional[str], +) -> pd.DataFrame: + """Convert input data to DataFrame""" + if isinstance(data, (list, np.ndarray)): + if all(param is None for param in [glu, timestamp, id]): + return pd.DataFrame({"gl": data}) + raise ValueError("Cannot process list/array data with column specifications. Please provide a DataFrame.") + + if isinstance(data, pd.Series): + if data.index.dtype.kind == "M": # datetime index + return pd.DataFrame({"time": data.index, "gl": data.values}) + return pd.DataFrame({"gl": data.values}) + + if not isinstance(data, pd.DataFrame): + raise TypeError("Could not convert data to DataFrame") + return data + + +def _find_column( + data: pd.DataFrame, column_name: Optional[str], default_name: str, original_columns: list, param_name: str +) -> str: + """Find and validate column name""" + if column_name is None: + if default_name not in data.columns: + raise ValueError(f"No {param_name} column specified and no '{default_name}' column found") + return default_name + + if not isinstance(column_name, str): + raise ValueError(f"User-defined {param_name} name must be string.") + + column_lower = column_name.lower() + if column_lower not in data.columns: + warnings.warn( + f"Could not find user-defined {param_name} argument name '{column_name}' in dataset. " + f"Available columns: {original_columns}", + stacklevel=2, + ) + + if default_name in data.columns: + raise ValueError( + f"Fix user-defined argument name for {param_name}. " + f"Note: A column in the dataset DOES match the name '{default_name}': " + f"If this is the correct column, indicate as such in function argument. " + f"i.e. {param_name} = '{default_name}'" + ) + else: + raise ValueError(f"Column '{column_name}' not found in data") + + return column_lower + + +def _process_id_column(data: pd.DataFrame, id: Optional[str], original_columns: list) -> pd.DataFrame: + """Process and validate ID column""" + if id is None: + print("No 'id' parameter passed, defaulting id to 1") + data.insert(0, "id", pd.Series(["1"] * len(data), dtype="string")) + return data + + id_col = _find_column(data, id, "id", original_columns, "id") + id_data = data[id_col] + data = data.drop(columns=[id_col]) + data.insert(0, "id", id_data.astype("string")) + return data + + +def _process_timestamp_column( + data: pd.DataFrame, timestamp: Optional[str], original_columns: list, time_parser: Callable +) -> pd.DataFrame: + """Process and validate timestamp column""" + timestamp_col = _find_column(data, timestamp, "time", original_columns, "timestamp") + + if "time" not in data.columns or timestamp_col != "time": + time_data = data[timestamp_col] + if timestamp_col != "time": + data = data.drop(columns=[timestamp_col]) + + try: + time_data = time_parser(time_data) + except Exception as e: + raise ValueError( + f"Failed to parse times, ensure times are in parsable format. Original error: {str(e)}" + ) from e + + data.insert(1, "time", time_data) + + data["time"] = pd.to_datetime(data["time"]).apply(localize_naive_timestamp) + return data + + +def _process_glucose_column(data: pd.DataFrame, glu: Optional[str], original_columns: list) -> pd.DataFrame: + """Process and validate glucose column""" + glu_col = _find_column(data, glu, "gl", original_columns, "glucose") + + # Check if glucose values are in mmol/L + mmol_conversion = glu and "mmol/l" in glu.lower() + + if "gl" not in data.columns or glu_col != "gl": + gl_data = data[glu_col] + if glu_col != "gl": + data = data.drop(columns=[glu_col]) + + try: + gl_data = pd.to_numeric(gl_data, errors="coerce") + except Exception as e: + raise ValueError(f"Failed to convert glucose values to numeric: {str(e)}") from e + + if mmol_conversion: + gl_data = gl_data * 18 + + data.insert(2, "gl", gl_data) + + return data + + +def _validate_glucose_values(data: pd.DataFrame) -> None: + """Validate glucose values and issue warnings if needed""" + if data["gl"].min() < 20: + warnings.warn("Minimum glucose reading below 20. Data may not be cleaned.", stacklevel=2) + if data["gl"].max() > 500: + warnings.warn("Maximum glucose reading above 500. Data may not be cleaned.", stacklevel=2) + + def process_data( data: Union[pd.DataFrame, pd.Series, list, np.ndarray], id: Optional[str] = None, timestamp: Optional[str] = None, glu: Optional[str] = None, - time_parser: Optional[Callable] = None + time_parser: Optional[Callable] = None, ) -> pd.DataFrame: """ Data Pre-Processor @@ -79,178 +211,27 @@ def process_data( >>> print(processed.columns.tolist()) ['id', 'time', 'gl'] """ - # Default time parser - if time_parser is None: - time_parser = pd.to_datetime - - # Validate input data type - if not isinstance(data, (pd.DataFrame, pd.Series, list, np.ndarray)): - raise TypeError("Invalid data type, please use DataFrame, Series, list, or numpy array.") - - # Convert to DataFrame if necessary - if isinstance(data, (list, np.ndarray)): - if glu is None and timestamp is None and id is None: - # Assume it's just glucose values - data = pd.DataFrame({'gl': data}) - else: - raise ValueError("Cannot process list/array data with column specifications. Please provide a DataFrame.") - - if isinstance(data, pd.Series): - if data.index.dtype.kind == 'M': # datetime index - data = pd.DataFrame({'time': data.index, 'gl': data.values}) - else: - data = pd.DataFrame({'gl': data.values}) - - # Ensure we have a DataFrame - if not isinstance(data, pd.DataFrame): - raise TypeError("Could not convert data to DataFrame") + time_parser = time_parser or pd.to_datetime - # Drop NAs + # Validate and convert input data + _validate_input_data(data) + data = _convert_to_dataframe(data, glu, timestamp, id) data = data.dropna() if data.empty: raise ValueError("No data remaining after removing NAs") - # Make column names lowercase for matching + # Normalize columns and process original_columns = data.columns.tolist() data.columns = [col.lower() if isinstance(col, str) else str(col).lower() for col in data.columns] - # Process id column - if id is None: - print("No 'id' parameter passed, defaulting id to 1") - data.insert(0, 'id', pd.Series(['1'] * len(data), dtype='string')) - else: - if not isinstance(id, str): - raise ValueError("User-defined id name must be string.") - - id_lower = id.lower() - if id_lower not in data.columns: - warning_msg = (f"Could not find user-defined id argument name '{id}' in dataset. " - f"Available columns: {original_columns}") - warnings.warn(warning_msg, stacklevel=2) - - # Check if there's a column named 'id' - if 'id' in data.columns: - raise ValueError("Fix user-defined argument name for id. " - "Note: A column in the dataset DOES match the name 'id': " - "If this is the correct column, indicate as such in function argument. " - "i.e. id = 'id'") - else: - raise ValueError(f"Column '{id}' not found in data") - - # Move id column to first position and rename - id_col = data[id_lower] - data = data.drop(columns=[id_lower]) - data.insert(0, 'id', id_col.astype('string')) - - # Process timestamp column - if timestamp is None: - if 'time' not in data.columns: - raise ValueError("No timestamp column specified and no 'time' column found") - timestamp_col = 'time' - else: - if not isinstance(timestamp, str): - raise ValueError("User-defined timestamp name must be string.") - - timestamp_lower = timestamp.lower() - if timestamp_lower not in data.columns: - warning_msg = (f"Could not find user-defined timestamp argument name '{timestamp}' in dataset. " - f"Available columns: {original_columns}") - warnings.warn(warning_msg, stacklevel=2) - - # Check if there's a column named 'time' - if 'time' in data.columns: - raise ValueError("Fix user-defined argument name for timestamp. " - "Note: A column in the dataset DOES match the name 'time': " - "If this is the correct column, indicate as such in function argument. " - "i.e. timestamp = 'time'") - else: - raise ValueError(f"Column '{timestamp}' not found in data") - - timestamp_col = timestamp_lower - - # Move timestamp column to second position and rename - if 'time' not in data.columns or timestamp_col != 'time': - time_data = data[timestamp_col] - if timestamp_col != 'time': - data = data.drop(columns=[timestamp_col]) - - # Parse time - try: - time_data = time_parser(time_data) - except Exception as e: - raise ValueError(f"Failed to parse times, ensure times are in parsable format. " - f"Original error: {str(e)}") from e - - # Insert at position 1 (after id) - data.insert(1, 'time', time_data) - - # localize time if in naive format - data["time"] = pd.to_datetime(data["time"]).apply(localize_naive_timestamp) - - # Process glucose column - if glu is None: - if 'gl' not in data.columns: - raise ValueError("No glucose column specified and no 'gl' column found") - glu_col = 'gl' - else: - if not isinstance(glu, str): - raise ValueError("User-defined glucose name must be string.") - - glu_lower = glu.lower() - if glu_lower not in data.columns: - warning_msg = (f"Could not find user-defined glucose argument name '{glu}' in dataset. " - f"Available columns: {original_columns}") - warnings.warn(warning_msg, stacklevel=2) - - # Check if there's a column named 'gl' - if 'gl' in data.columns: - raise ValueError("Fix user-defined argument name for glucose. " - "Note: A column in the dataset DOES match the name 'gl': " - "If this is the correct column, indicate as such in function argument. " - "i.e. glu = 'gl'") - else: - raise ValueError(f"Column '{glu}' not found in data") - - glu_col = glu_lower - - # Check if glucose values are in mmol/L - mmol_conversion = False - if glu and 'mmol/l' in glu.lower(): - mmol_conversion = True - - # Move glucose column to third position and rename - if 'gl' not in data.columns or glu_col != 'gl': - gl_data = data[glu_col] - if glu_col != 'gl': - data = data.drop(columns=[glu_col]) - - # Convert to numeric - try: - gl_data = pd.to_numeric(gl_data, errors='coerce') - except Exception as e: - raise ValueError(f"Failed to convert glucose values to numeric: {str(e)}") from e - - # Convert mmol/L to mg/dL if needed - if mmol_conversion: - gl_data = gl_data * 18 - - # Insert at position 2 (after id and time) - data.insert(2, 'gl', gl_data) - - # Validation warnings - if data['gl'].min() < 20: - warnings.warn("Minimum glucose reading below 20. Data may not be cleaned.", stacklevel=2) - - if data['gl'].max() > 500: - warnings.warn("Maximum glucose reading above 500. Data may not be cleaned.", stacklevel=2) - - # Keep only the three required columns in correct order - data = data[['id', 'time', 'gl']] - - # Drop rows with NaN glucose values - data = data.dropna(subset=['gl']) + data = _process_id_column(data, id, original_columns) + data = _process_timestamp_column(data, timestamp, original_columns, time_parser) + data = _process_glucose_column(data, glu, original_columns) + _validate_glucose_values(data) + # Final cleanup + data = data[["id", "time", "gl"]].dropna(subset=["gl"]) if data.empty: raise ValueError("No valid data remaining after processing") diff --git a/iglu_python/quantile_glu.py b/iglu_python/quantile_glu.py index 20e9d16..ecae933 100644 --- a/iglu_python/quantile_glu.py +++ b/iglu_python/quantile_glu.py @@ -8,7 +8,7 @@ def quantile_glu( data: Union[pd.DataFrame, pd.Series, np.ndarray, list], quantiles: List[float] = None -) -> pd.DataFrame|list[float]: +) -> pd.DataFrame | list[float]: """ Calculate glucose level quantiles. @@ -71,11 +71,7 @@ def quantile_glu( # Calculate quantiles for each subject and unstack to columns result = ( data.groupby("id")["gl"] - .apply( - lambda x: pd.Series( - np.quantile(x.dropna(), np.array(quantiles) / 100), index=quantiles - ) - ) + .apply(lambda x: pd.Series(np.quantile(x.dropna(), np.array(quantiles) / 100), index=quantiles)) .unstack() .reset_index() ) diff --git a/iglu_python/range_glu.py b/iglu_python/range_glu.py index c94ca37..9b7fd06 100644 --- a/iglu_python/range_glu.py +++ b/iglu_python/range_glu.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def range_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame|float: +def range_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame | float: """ Calculate glucose level range. @@ -56,8 +56,6 @@ def range_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.Data data = check_data_columns(data) # Calculate range for each subject - result = ( - data.groupby("id").agg(range=("gl", lambda x: x.max() - x.min())).reset_index() - ) + result = data.groupby("id").agg(range=("gl", lambda x: x.max() - x.min())).reset_index() return result diff --git a/iglu_python/roc.py b/iglu_python/roc.py index b75d8d8..b2a2349 100644 --- a/iglu_python/roc.py +++ b/iglu_python/roc.py @@ -87,11 +87,7 @@ def roc( 3 NaN """ - def roc_single(data: pd.DataFrame, - timelag: int, - dt0: int = None , - inter_gap: int = 45, - tz: str = "") -> np.ndarray: + def roc_single(data: pd.DataFrame, timelag: int, dt0: int = None, inter_gap: int = 45, tz: str = "") -> np.ndarray: """Calculate ROC for a single subject's data""" data_ip = CGMS2DayByDay(data, dt0=dt0, inter_gap=inter_gap, tz=tz) gl_ip_vec = data_ip[0].flatten() # Flatten the interpolated glucose matrix @@ -145,9 +141,7 @@ def roc_single(data: pd.DataFrame, roc_values = roc_single(subject_data, timelag, dt0, inter_gap, tz) # Create time points for ROC values - time_points = pd.date_range( - start=subject_data["time"].min(), periods=len(roc_values), freq=f"{dt0}min" - ) + time_points = pd.date_range(start=subject_data["time"].min(), periods=len(roc_values), freq=f"{dt0}min") # Add ROC values to result for t, r in zip(time_points, roc_values, strict=False): diff --git a/iglu_python/sd_glu.py b/iglu_python/sd_glu.py index 42d4899..0722018 100644 --- a/iglu_python/sd_glu.py +++ b/iglu_python/sd_glu.py @@ -6,7 +6,7 @@ from .utils import check_data_columns -def sd_glu(data: Union[pd.DataFrame, list, np.ndarray, pd.Series]) -> pd.DataFrame|float: +def sd_glu(data: Union[pd.DataFrame, list, np.ndarray, pd.Series]) -> pd.DataFrame | float: """ Calculate standard deviation of glucose values. @@ -46,7 +46,7 @@ def sd_glu(data: Union[pd.DataFrame, list, np.ndarray, pd.Series]) -> pd.DataFra """ # Handle Series input if isinstance(data, (list, np.ndarray, pd.Series)): - if isinstance(data, (list,np.ndarray)): + if isinstance(data, (list, np.ndarray)): data = pd.Series(data) return data.std(ddof=1) diff --git a/iglu_python/sd_measures.py b/iglu_python/sd_measures.py index 8d0db02..8eb9042 100644 --- a/iglu_python/sd_measures.py +++ b/iglu_python/sd_measures.py @@ -7,10 +7,9 @@ from .utils import CGMS2DayByDay, check_data_columns -def sd_measures(data: pd.DataFrame|pd.Series, - dt0: Optional[int] = None, - inter_gap: int = 45, - tz: str = "") -> pd.DataFrame|dict[str, float]: +def sd_measures( + data: pd.DataFrame | pd.Series, dt0: Optional[int] = None, inter_gap: int = 45, tz: str = "" +) -> pd.DataFrame | dict[str, float]: """ Calculate SD subtypes for glucose variability analysis @@ -87,22 +86,21 @@ def sd_measures(data: pd.DataFrame|pd.Series, # Convert the dictionary results into a DataFrame with proper columns results = [] - for subject_id in data['id'].unique(): - subject_data = data[data['id'] == subject_id] + for subject_id in data["id"].unique(): + subject_data = data[data["id"] == subject_id] result_dict = sd_measures_single(subject_data, dt0, inter_gap, tz) - result_dict['id'] = subject_id + result_dict["id"] = subject_id results.append(result_dict) # convert result into dataframe with 'id' on the first place out = pd.DataFrame(results) - out = out[['id'] + list(out.columns[:-1])] + out = out[["id"] + list(out.columns[:-1])] return out -def sd_measures_single(data: pd.DataFrame, - dt0: Optional[int] = None, - inter_gap: int = 45, - tz: str = "") -> dict[str, float]: +def sd_measures_single( + data: pd.DataFrame, dt0: Optional[int] = None, inter_gap: int = 45, tz: str = "" +) -> dict[str, float]: gd2d, actual_dates, gd2d_dt0 = CGMS2DayByDay(data, tz=tz, dt0=dt0, inter_gap=inter_gap) return _calculate_sd_subtypes(gd2d, gd2d_dt0) @@ -131,12 +129,12 @@ def _calculate_sd_subtypes(gd2d: np.ndarray, dt0: int) -> Dict[str, Any]: # 1. SDw - vertical within days # Standard deviation within each day, then mean across days daily_sds = _safe_nanstd(gd2d, axis=1, ddof=1) # ddof=1 for sample std - result['SDw'] = _safe_nanmean(daily_sds) + result["SDw"] = _safe_nanmean(daily_sds) # 2. SDhhmm - between time points # Mean at each time point across days, then SD of those means timepoint_means = _safe_nanmean(gd2d, axis=0) - result['SDhhmm'] = _safe_nanstd(timepoint_means, ddof=1) + result["SDhhmm"] = _safe_nanstd(timepoint_means, ddof=1) # 3. SDwsh - within series (1-hour windows) # Rolling standard deviation over 1-hour windows @@ -145,24 +143,24 @@ def _calculate_sd_subtypes(gd2d: np.ndarray, dt0: int) -> Dict[str, Any]: # Calculate rolling standard deviation rolling_sds = _rolling_std(gs, window=win) - result['SDwsh'] = _safe_nanmean(rolling_sds) + result["SDwsh"] = _safe_nanmean(rolling_sds) # 4. SDdm - horizontal sd (between daily means) # Standard deviation of daily mean glucose values daily_means = _safe_nanmean(gd2d, axis=1) - result['SDdm'] = _safe_nanstd(daily_means, ddof=1) + result["SDdm"] = _safe_nanstd(daily_means, ddof=1) # 5. SDb - between days, within timepoints # SD across days for each time point, then mean of those SDs timepoint_sds = _safe_nanstd(gd2d, axis=0, ddof=1) - result['SDb'] = _safe_nanmean(timepoint_sds) + result["SDb"] = _safe_nanmean(timepoint_sds) # 6. SDbdm - between days, within timepoints, corrected for daily means # Subtract daily mean from each value, then calculate SDb on corrected values daily_means_matrix = daily_means[:, np.newaxis] # Convert to column vector corrected_gd2d = gd2d - daily_means_matrix corrected_timepoint_sds = _safe_nanstd(corrected_gd2d, axis=0, ddof=1) - result['SDbdm'] = _safe_nanmean(corrected_timepoint_sds) + result["SDbdm"] = _safe_nanmean(corrected_timepoint_sds) return result @@ -183,7 +181,7 @@ def _rolling_std(data: np.ndarray, window: int) -> np.ndarray: np.ndarray Rolling standard deviations (trimmed to valid windows only) """ - #valid_data = data[~np.isnan(data)] + # valid_data = data[~np.isnan(data)] valid_data = np.concatenate([data, np.full(window, np.nan)]) # add nan tail to match R n = len(valid_data) @@ -193,12 +191,13 @@ def _rolling_std(data: np.ndarray, window: int) -> np.ndarray: rolling_stds = [] for i in range(n - window + 1): - window_data = valid_data[i:i + window] + window_data = valid_data[i : i + window] if len(window_data) == window: # Full window rolling_stds.append(_safe_nanstd(window_data, ddof=1)) return np.array(rolling_stds) if rolling_stds else np.array([np.nan]) + def _safe_nanstd(data: np.ndarray, axis: Optional[int] = None, ddof: int = 1) -> float: """ Safe version of np.nanstd that handles insufficient data gracefully @@ -264,10 +263,9 @@ def _safe_nanmean(data: np.ndarray, axis: Optional[int] = None) -> float: # Alternative vectorized implementation for better performance -def sd_measures_vectorized(data: pd.DataFrame, - dt0: Optional[int] = None, - inter_gap: int = 45, - tz: str = "") -> pd.DataFrame: +def sd_measures_vectorized( + data: pd.DataFrame, dt0: Optional[int] = None, inter_gap: int = 45, tz: str = "" +) -> pd.DataFrame: """ Vectorized version of sd_measures for better performance with large datasets """ @@ -276,8 +274,8 @@ def sd_measures_vectorized(data: pd.DataFrame, results = [] current_dt0 = dt0 - for i, subject_id in enumerate(data['id'].unique()): - subject_data = data[data['id'] == subject_id].copy() + for i, subject_id in enumerate(data["id"].unique()): + subject_data = data[data["id"] == subject_id].copy() gd2d, actual_dates, gd2d_dt0 = CGMS2DayByDay(subject_data, tz=tz, dt0=current_dt0, inter_gap=inter_gap) if i == 0: current_dt0 = gd2d_dt0 @@ -296,12 +294,11 @@ def _calculate_sd_subtypes_vectorized(gd2d: np.ndarray, dt0: int, subject_id: An warnings.simplefilter("ignore", category=RuntimeWarning) return { - 'id': subject_id, - 'SDw': _safe_nanmean(np.nanstd(gd2d, axis=1, ddof=1)), - 'SDhhmm': np.nanstd(_safe_nanmean(gd2d, axis=0), ddof=1), - 'SDwsh': _safe_nanmean(_rolling_std(gd2d.T.flatten(), round(60/dt0))), - 'SDdm': np.nanstd(_safe_nanmean(gd2d, axis=1), ddof=1), - 'SDb': _safe_nanmean(np.nanstd(gd2d, axis=0, ddof=1)), - 'SDbdm': _safe_nanmean(np.nanstd(gd2d - _safe_nanmean(gd2d, axis=1, keepdims=True), - axis=0, ddof=1)) + "id": subject_id, + "SDw": _safe_nanmean(np.nanstd(gd2d, axis=1, ddof=1)), + "SDhhmm": np.nanstd(_safe_nanmean(gd2d, axis=0), ddof=1), + "SDwsh": _safe_nanmean(_rolling_std(gd2d.T.flatten(), round(60 / dt0))), + "SDdm": np.nanstd(_safe_nanmean(gd2d, axis=1), ddof=1), + "SDb": _safe_nanmean(np.nanstd(gd2d, axis=0, ddof=1)), + "SDbdm": _safe_nanmean(np.nanstd(gd2d - _safe_nanmean(gd2d, axis=1, keepdims=True), axis=0, ddof=1)), } diff --git a/iglu_python/sd_roc.py b/iglu_python/sd_roc.py index e60fd4e..2e71f55 100644 --- a/iglu_python/sd_roc.py +++ b/iglu_python/sd_roc.py @@ -13,7 +13,7 @@ def sd_roc( dt0: int = 5, inter_gap: int = 45, tz: str = "", -) -> pd.DataFrame|float: +) -> pd.DataFrame | float: """ Calculate the standard deviation of the rate of change. @@ -96,19 +96,19 @@ def sd_roc( # Validate input data data = check_data_columns(data, tz=tz) - data.set_index('time', drop=True, inplace=True) + data.set_index("time", drop=True, inplace=True) # Calculate ROC values for all subjects - out = data.groupby('id').apply(lambda x: sd_roc_single(x['gl'], timelag, dt0, inter_gap, tz)).reset_index() - out.columns = ['id', 'sd_roc'] + results = [] + for subject_id, group in data.groupby("id"): + sd_roc_value = sd_roc_single(group["gl"], timelag, dt0, inter_gap, tz) + results.append({"id": subject_id, "sd_roc": sd_roc_value}) + + out = pd.DataFrame(results) return out -def sd_roc_single(data: pd.Series, - timelag: int = 15, - dt0: int = 5, - inter_gap: int = 45, - tz: str = "") -> float: +def sd_roc_single(data: pd.Series, timelag: int = 15, dt0: int = 5, inter_gap: int = 45, tz: str = "") -> float: roc_data = roc(data, timelag=timelag, dt0=dt0, inter_gap=inter_gap, tz=tz) - sd_roc = np.nanstd(roc_data.dropna()['roc'], ddof=1) + sd_roc = np.nanstd(roc_data.dropna()["roc"], ddof=1) return sd_roc diff --git a/iglu_python/summary_glu.py b/iglu_python/summary_glu.py index c7951ef..21c07bd 100644 --- a/iglu_python/summary_glu.py +++ b/iglu_python/summary_glu.py @@ -7,7 +7,7 @@ from .utils import check_data_columns -def summary_glu(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.DataFrame|dict[str,float]: +def summary_glu(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.DataFrame | dict[str, float]: """ Calculate summary glucose level @@ -50,7 +50,6 @@ def summary_glu(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.Da # Handle vector input (Series, list, or numpy array) if isinstance(data, (pd.Series, list, np.ndarray)): - # Convert to numpy array for consistent handling if isinstance(data, pd.Series): glucose_values = data.values @@ -79,33 +78,33 @@ def summary_glu(data: Union[pd.DataFrame, pd.Series, list, np.ndarray]) -> pd.Da # Filter out missing glucose values and group by id result_rows = [] - for subject_id in data['id'].unique(): - subject_data = data[data['id'] == subject_id] - glucose_values = subject_data['gl'].dropna().values + for subject_id in data["id"].unique(): + subject_data = data[data["id"] == subject_id] + glucose_values = subject_data["gl"].dropna().values if len(glucose_values) == 0: warnings.warn(f"No valid glucose values found for subject {subject_id}", stacklevel=2) # Still include the subject with NaN values summary_stats = { - 'Min.': np.nan, - '1st Qu.': np.nan, - 'Median': np.nan, - 'Mean': np.nan, - '3rd Qu.': np.nan, - 'Max.': np.nan + "Min.": np.nan, + "1st Qu.": np.nan, + "Median": np.nan, + "Mean": np.nan, + "3rd Qu.": np.nan, + "Max.": np.nan, } else: summary_stats = _calculate_summary_stats(glucose_values) # Add subject id to the summary - summary_stats['id'] = subject_id + summary_stats["id"] = subject_id result_rows.append(summary_stats) # Create result DataFrame with id column first result_df = pd.DataFrame(result_rows) # Reorder columns to match R output (id first, then summary stats) - column_order = ['id', 'Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] + column_order = ["id", "Min.", "1st Qu.", "Median", "Mean", "3rd Qu.", "Max."] return result_df[column_order] @@ -126,10 +125,10 @@ def _calculate_summary_stats(glucose_values: np.ndarray) -> dict: Dictionary with summary statistics matching R's summary() output """ return { - 'Min.': np.min(glucose_values), - '1st Qu.': np.percentile(glucose_values, 25), - 'Median': np.median(glucose_values), - 'Mean': np.mean(glucose_values), - '3rd Qu.': np.percentile(glucose_values, 75), - 'Max.': np.max(glucose_values) + "Min.": np.min(glucose_values), + "1st Qu.": np.percentile(glucose_values, 25), + "Median": np.median(glucose_values), + "Mean": np.mean(glucose_values), + "3rd Qu.": np.percentile(glucose_values, 75), + "Max.": np.max(glucose_values), } diff --git a/iglu_python/utils.py b/iglu_python/utils.py index e487f73..4f30aaf 100644 --- a/iglu_python/utils.py +++ b/iglu_python/utils.py @@ -10,14 +10,17 @@ _IGLU_R_COMPATIBLE = True + def set_iglu_r_compatible(value: bool) -> None: global _IGLU_R_COMPATIBLE _IGLU_R_COMPATIBLE = value + def is_iglu_r_compatible() -> bool: global _IGLU_R_COMPATIBLE return _IGLU_R_COMPATIBLE + def localize_naive_timestamp(timestamp: datetime) -> datetime: """ Localize a naive timestamp to the local timezone. @@ -36,7 +39,8 @@ def set_local_tz(tz: str) -> None: global local_tz local_tz = ZoneInfo(tz) -def get_local_tz() : + +def get_local_tz(): global local_tz return local_tz @@ -120,7 +124,7 @@ def check_data_columns(data: pd.DataFrame, time_check=False, tz="") -> pd.DataFr def CGMS2DayByDay( - data: pd.DataFrame|pd.Series, + data: pd.DataFrame | pd.Series, dt0: Optional[pd.Timestamp] = None, inter_gap: int = 45, tz: str = "", @@ -195,9 +199,7 @@ def CGMS2DayByDay( # Create time grid start_time = data["time"].min().floor("D") end_time = data["time"].max().ceil("D") - time_grid = pd.date_range( - start=start_time, end=end_time, freq=f"{dt0}min" - ) + time_grid = pd.date_range(start=start_time, end=end_time, freq=f"{dt0}min") if is_iglu_r_compatible(): # remove the first time point time_grid = time_grid[1:] @@ -208,9 +210,7 @@ def CGMS2DayByDay( # find gaps in the data (using original data indexes, not time grid) gaps = [] for i in range(len(data) - 1): - if ( - data["time"].iloc[i + 1] - data["time"].iloc[i] - ).total_seconds() > inter_gap * 60: + if (data["time"].iloc[i + 1] - data["time"].iloc[i]).total_seconds() > inter_gap * 60: gaps.append((i, i + 1)) # Interpolate glucose values @@ -227,15 +227,14 @@ def CGMS2DayByDay( gap_start_idx = gap[0] gap_start_time = data["time"].iloc[gap_start_idx] # find the index of the gap start in the time grid - gap_start_idx_in_time_grid = int( - np.floor((gap_start_time - start_time).total_seconds() / (60 * dt0)) - ) + gap_start_idx_in_time_grid = int(np.floor((gap_start_time - start_time).total_seconds() / (60 * dt0))) gap_end_idx = gap[1] gap_end_time = data["time"].iloc[gap_end_idx] # find the index of the gap end in the time grid gap_end_idx_in_time_grid = int( # -1sec to indicate time before measurement - np.floor(((gap_end_time - start_time).total_seconds() -1 ) / (60 * dt0))) + np.floor(((gap_end_time - start_time).total_seconds() - 1) / (60 * dt0)) + ) # put nan in the gap interp_data[gap_start_idx_in_time_grid:gap_end_idx_in_time_grid] = np.nan @@ -260,6 +259,7 @@ def CGMS2DayByDay( return interp_data, actual_dates, dt0 + def gd2d_to_df(gd2d, actual_dates, dt0): """Convert gd2d (CGMS2DayByDay output) to a pandas DataFrame""" df = pd.DataFrame({"time": [], "gl": []}) @@ -271,9 +271,6 @@ def gd2d_to_df(gd2d, actual_dates, dt0): day_time = [pd.Timedelta(i * dt0, unit="m") + actual_dates[day] for i in range(n)] time.extend(day_time) - df = pd.DataFrame({ - "time": pd.Series(time), - "gl": pd.Series(gl, dtype='float64') - }) + df = pd.DataFrame({"time": pd.Series(time), "gl": pd.Series(gl, dtype="float64")}) return df diff --git a/iglu_r_discrepancies.ipynb b/iglu_r_discrepancies.ipynb index 98ee64c..e31841f 100644 --- a/iglu_r_discrepancies.ipynb +++ b/iglu_r_discrepancies.ipynb @@ -49,7 +49,7 @@ "iglu_version = str(ro.r('packageVersion(\"iglu\")'))\n", "print(f\"iglu version: {iglu_version}\")\n", "print(f\"iglu_py version: {version('iglu-py')}\")\n", - "print(f\"rpy2 version: {version('rpy2')}\")\n" + "print(f\"rpy2 version: {version('rpy2')}\")" ] }, { @@ -67,18 +67,14 @@ "source": [ "@bridge.df_conversion\n", "def my_CGMS2DayByDay(data: pd.DataFrame, **kwargs):\n", - "\n", " r_named_list = bridge.iglu_r.CGMS2DayByDay(data, **kwargs)\n", "\n", - " result = {\n", - " name: ro.conversion.rpy2py(r_named_list[i])\n", - " for i, name in enumerate(r_named_list.names())\n", - " }\n", + " result = {name: ro.conversion.rpy2py(r_named_list[i]) for i, name in enumerate(r_named_list.names())}\n", "\n", - " result['actual_dates'] = [pd.to_datetime(d, unit='D', origin='1970-01-01') for d in result['actual_dates']]\n", - " result['dt0'] = result['dt0'][0]\n", + " result[\"actual_dates\"] = [pd.to_datetime(d, unit=\"D\", origin=\"1970-01-01\") for d in result[\"actual_dates\"]]\n", + " result[\"dt0\"] = result[\"dt0\"][0]\n", "\n", - " return result\n" + " return result" ] }, { @@ -168,16 +164,20 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1', 'subject1', 'subject1', 'subject1'],\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 00:00:00', # 0 min\n", - " '2020-01-01 00:05:00', # 5 min\n", - " '2020-01-01 00:10:00', # 10 min\n", - " '2020-01-01 00:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\", \"subject1\", \"subject1\", \"subject1\"],\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 00:00:00\", # 0 min\n", + " \"2020-01-01 00:05:00\", # 5 min\n", + " \"2020-01-01 00:10:00\", # 10 min\n", + " \"2020-01-01 00:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165],\n", + " }\n", + ")\n", "display(data)" ] }, @@ -209,17 +209,18 @@ "source": [ "r_result = my_CGMS2DayByDay(data)\n", "\n", - "gd2d = r_result['gd2d']\n", - "actual_dates = r_result['actual_dates']\n", - "dt0 = r_result['dt0']\n", - "\n", - "print(f\"gd2d.shape={gd2d.shape} \\t/ expected (1,288)\") # expected (1,288)\n", - "print(f\"actual_dates={actual_dates} \\t/ expected [Timestamp('2020-01-01 00:00:00')]\") # expected [datetime.date(2020, 1, 1)]\n", - "print(f\"dt0={dt0}\") # expected 5\n", - "print(f\"gd2d[:,0:5]=\\n{gd2d[:,0:5]} \\t/ expected [[150. 155. 160. 165. nan]]\") # expected [[150. 155. 160. 165. nan]]\n", + "gd2d = r_result[\"gd2d\"]\n", + "actual_dates = r_result[\"actual_dates\"]\n", + "dt0 = r_result[\"dt0\"]\n", "\n", - "\n", - "\n" + "print(f\"gd2d.shape={gd2d.shape} \\t/ expected (1,288)\") # expected (1,288)\n", + "print(\n", + " f\"actual_dates={actual_dates} \\t/ expected [Timestamp('2020-01-01 00:00:00')]\"\n", + ") # expected [datetime.date(2020, 1, 1)]\n", + "print(f\"dt0={dt0}\") # expected 5\n", + "print(\n", + " f\"gd2d[:,0:5]=\\n{gd2d[:, 0:5]} \\t/ expected [[150. 155. 160. 165. nan]]\"\n", + ") # expected [[150. 155. 160. 165. nan]]" ] }, { @@ -294,17 +295,13 @@ "source": [ "hours = 1\n", "dt0 = 5\n", - "samples = int(hours*60/dt0)\n", - "times = pd.date_range('2020-01-01', periods=samples, freq=f\"{dt0}min\")\n", - "glucose_values = [80,120]* int(samples/2)\n", + "samples = int(hours * 60 / dt0)\n", + "times = pd.date_range(\"2020-01-01\", periods=samples, freq=f\"{dt0}min\")\n", + "glucose_values = [80, 120] * int(samples / 2)\n", "\n", - "syntheticdata = pd.DataFrame({\n", - " 'id': ['subject1'] * samples,\n", - " 'time': times,\n", - " 'gl': glucose_values\n", - "})\n", + "syntheticdata = pd.DataFrame({\"id\": [\"subject1\"] * samples, \"time\": times, \"gl\": glucose_values})\n", "\n", - "synthetic_iglu_auc_results = iglu_py.auc(syntheticdata)\n", + "synthetic_iglu_auc_results = iglu_py.auc(syntheticdata)\n", "synthetic_iglu_auc_results" ] }, @@ -334,17 +331,17 @@ } ], "source": [ - "r_result = my_CGMS2DayByDay(data,tz=\"UTC\")\n", + "r_result = my_CGMS2DayByDay(data, tz=\"UTC\")\n", "\n", - "gd2d = r_result['gd2d']\n", - "actual_dates = r_result['actual_dates']\n", - "dt0 = r_result['dt0']\n", + "gd2d = r_result[\"gd2d\"]\n", + "actual_dates = r_result[\"actual_dates\"]\n", + "dt0 = r_result[\"dt0\"]\n", "\n", - "print(gd2d.shape) # expected (1,288)\n", - "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", - "print(dt0) # expected 5\n", + "print(gd2d.shape) # expected (1,288)\n", + "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", + "print(dt0) # expected 5\n", "\n", - "print(gd2d[:,0:5]) # expected [[150. 155. 160. 165. nan]]" + "print(gd2d[:, 0:5]) # expected [[150. 155. 160. 165. nan]]" ] }, { @@ -435,16 +432,20 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1', 'subject1', 'subject1', 'subject1'],\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 10:00:00', # 0 min\n", - " '2020-01-01 10:05:00', # 5 min\n", - " '2020-01-01 10:10:00', # 10 min\n", - " '2020-01-01 10:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\", \"subject1\", \"subject1\", \"subject1\"],\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 10:00:00\", # 0 min\n", + " \"2020-01-01 10:05:00\", # 5 min\n", + " \"2020-01-01 10:10:00\", # 10 min\n", + " \"2020-01-01 10:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165],\n", + " }\n", + ")\n", "display(data)" ] }, @@ -471,18 +472,18 @@ "source": [ "r_result = my_CGMS2DayByDay(data)\n", "\n", - "gd2d = r_result['gd2d']\n", - "actual_dates = r_result['actual_dates']\n", - "dt0 = r_result['dt0']\n", + "gd2d = r_result[\"gd2d\"]\n", + "actual_dates = r_result[\"actual_dates\"]\n", + "dt0 = r_result[\"dt0\"]\n", "\n", - "print(gd2d.shape) # expected (1,288)\n", - "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", - "print(dt0) # expected 5\n", + "print(gd2d.shape) # expected (1,288)\n", + "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", + "print(dt0) # expected 5\n", "\n", - "indx_10am = int((60/dt0) * 10)\n", + "indx_10am = int((60 / dt0) * 10)\n", "print(indx_10am)\n", - "print(gd2d[:,indx_10am:indx_10am+6]) # expected [[ 150. 155. 160. 165. nan nan]\n", - "print(gd2d[:,indx_10am-1:indx_10am+5]) # but we'll get expected on one position left\n" + "print(gd2d[:, indx_10am : indx_10am + 6]) # expected [[ 150. 155. 160. 165. nan nan]\n", + "print(gd2d[:, indx_10am - 1 : indx_10am + 5]) # but we'll get expected on one position left" ] }, { @@ -602,20 +603,24 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1']*8,\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 00:00:00', # 0 min\n", - " '2020-01-01 00:05:00', # 5 min\n", - " '2020-01-01 00:10:00', # 10 min\n", - " '2020-01-01 00:15:00', # 15 min\n", - " '2020-01-02 00:00:00', # 0 min\n", - " '2020-01-02 00:05:00', # 5 min\n", - " '2020-01-02 00:10:00', # 10 min\n", - " '2020-01-02 00:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165]*2\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\"] * 8,\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 00:00:00\", # 0 min\n", + " \"2020-01-01 00:05:00\", # 5 min\n", + " \"2020-01-01 00:10:00\", # 10 min\n", + " \"2020-01-01 00:15:00\", # 15 min\n", + " \"2020-01-02 00:00:00\", # 0 min\n", + " \"2020-01-02 00:05:00\", # 5 min\n", + " \"2020-01-02 00:10:00\", # 10 min\n", + " \"2020-01-02 00:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165] * 2,\n", + " }\n", + ")\n", "display(data)" ] }, @@ -641,18 +646,18 @@ } ], "source": [ - "r_result = my_CGMS2DayByDay(data,tz=\"UTC\")\n", + "r_result = my_CGMS2DayByDay(data, tz=\"UTC\")\n", "\n", - "gd2d = r_result['gd2d']\n", - "actual_dates = r_result['actual_dates']\n", - "dt0 = r_result['dt0']\n", + "gd2d = r_result[\"gd2d\"]\n", + "actual_dates = r_result[\"actual_dates\"]\n", + "dt0 = r_result[\"dt0\"]\n", "\n", - "print(gd2d.shape) # expected (1,288)\n", - "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", - "print(dt0) # expected 5\n", + "print(gd2d.shape) # expected (1,288)\n", + "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", + "print(dt0) # expected 5\n", "\n", - "print(gd2d[:,0:5]) # expected [[150. 155. 160. 165. nan]]\n", - "print(gd2d[:,283:])" + "print(gd2d[:, 0:5]) # expected [[150. 155. 160. 165. nan]]\n", + "print(gd2d[:, 283:])" ] }, { @@ -771,20 +776,24 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1']*8,\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 23:40:00', # 0 min\n", - " '2020-01-01 23:45:00', # 5 min\n", - " '2020-01-01 23:50:00', # 10 min\n", - " '2020-01-01 23:55:00', # 15 min\n", - " '2020-01-02 00:00:00', # 0 min\n", - " '2020-01-02 00:05:00', # 5 min\n", - " '2020-01-02 00:10:00', # 10 min\n", - " '2020-01-02 00:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165, 170, 175, 180, 185]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\"] * 8,\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 23:40:00\", # 0 min\n", + " \"2020-01-01 23:45:00\", # 5 min\n", + " \"2020-01-01 23:50:00\", # 10 min\n", + " \"2020-01-01 23:55:00\", # 15 min\n", + " \"2020-01-02 00:00:00\", # 0 min\n", + " \"2020-01-02 00:05:00\", # 5 min\n", + " \"2020-01-02 00:10:00\", # 10 min\n", + " \"2020-01-02 00:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165, 170, 175, 180, 185],\n", + " }\n", + ")\n", "display(data)" ] }, @@ -808,18 +817,18 @@ } ], "source": [ - "r_result = my_CGMS2DayByDay(data,tz=\"UTC\")\n", + "r_result = my_CGMS2DayByDay(data, tz=\"UTC\")\n", "\n", - "gd2d = r_result['gd2d']\n", - "actual_dates = r_result['actual_dates']\n", - "dt0 = r_result['dt0']\n", + "gd2d = r_result[\"gd2d\"]\n", + "actual_dates = r_result[\"actual_dates\"]\n", + "dt0 = r_result[\"dt0\"]\n", "\n", - "print(gd2d.shape) # expected (1,288)\n", - "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", - "print(dt0) # expected 5\n", + "print(gd2d.shape) # expected (1,288)\n", + "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", + "print(dt0) # expected 5\n", "\n", - "print(gd2d[:,280:])\n", - "print(gd2d[:,:8]) # expected [[150. 155. 160. 165. nan]]" + "print(gd2d[:, 280:])\n", + "print(gd2d[:, :8]) # expected [[150. 155. 160. 165. nan]]" ] }, { @@ -844,8 +853,7 @@ "source": [ "@bridge.df_conversion\n", "def my_check_data_columns(data: pd.DataFrame, **kwargs):\n", - "\n", - " return bridge.iglu_r.check_data_columns(data, **kwargs)\n" + " return bridge.iglu_r.check_data_columns(data, **kwargs)" ] }, { @@ -987,16 +995,20 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1', 'subject1', 'subject1', 'subject1'],\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 00:00:00', # 0 min\n", - " '2020-01-01 00:05:00', # 5 min\n", - " '2020-01-01 00:10:00', # 10 min\n", - " '2020-01-01 00:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\", \"subject1\", \"subject1\", \"subject1\"],\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 00:00:00\", # 0 min\n", + " \"2020-01-01 00:05:00\", # 5 min\n", + " \"2020-01-01 00:10:00\", # 10 min\n", + " \"2020-01-01 00:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165],\n", + " }\n", + ")\n", "\n", "display(data)\n", "\n", @@ -1151,20 +1163,24 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1', 'subject1', 'subject1', 'subject1'],\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 00:00:00', # 0 min\n", - " '2020-01-01 00:05:00', # 5 min\n", - " '2020-01-01 00:10:00', # 10 min\n", - " '2020-01-01 00:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\", \"subject1\", \"subject1\", \"subject1\"],\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 00:00:00\", # 0 min\n", + " \"2020-01-01 00:05:00\", # 5 min\n", + " \"2020-01-01 00:10:00\", # 10 min\n", + " \"2020-01-01 00:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165],\n", + " }\n", + ")\n", "\n", "display(data)\n", "\n", - "r_result = my_check_data_columns(data,tz=\"UTC\")\n", + "r_result = my_check_data_columns(data, tz=\"UTC\")\n", "\n", "display(r_result)" ] @@ -1317,16 +1333,20 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1', 'subject1', 'subject1', 'subject1'],\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 00:00:00', # 0 min\n", - " '2020-01-01 00:05:00', # 5 min\n", - " '2020-01-01 00:10:00', # 10 min\n", - " '2020-01-01 00:15:00', # 15 min\n", - " ]),\n", - " 'gl': [150, 155, 160, 165]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\", \"subject1\", \"subject1\", \"subject1\"],\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 00:00:00\", # 0 min\n", + " \"2020-01-01 00:05:00\", # 5 min\n", + " \"2020-01-01 00:10:00\", # 10 min\n", + " \"2020-01-01 00:15:00\", # 15 min\n", + " ]\n", + " ),\n", + " \"gl\": [150, 155, 160, 165],\n", + " }\n", + ")\n", "\n", "display(data)\n", "\n", @@ -1483,20 +1503,24 @@ } ], "source": [ - "data = pd.DataFrame({\n", - " 'id': ['subject1', 'subject1', 'subject1', 'subject1'],\n", - " 'time': pd.to_datetime([\n", - " '2020-01-01 00:00:00', # 0 min\n", - " '2020-01-01 00:05:00', # 5 min\n", - " '2020-01-01 00:10:00', # 10 min\n", - " '2020-01-01 00:15:00', # 15 min\n", - " ]).tz_localize('UTC'),\n", - " 'gl': [150, 155, 160, 165]\n", - "})\n", + "data = pd.DataFrame(\n", + " {\n", + " \"id\": [\"subject1\", \"subject1\", \"subject1\", \"subject1\"],\n", + " \"time\": pd.to_datetime(\n", + " [\n", + " \"2020-01-01 00:00:00\", # 0 min\n", + " \"2020-01-01 00:05:00\", # 5 min\n", + " \"2020-01-01 00:10:00\", # 10 min\n", + " \"2020-01-01 00:15:00\", # 15 min\n", + " ]\n", + " ).tz_localize(\"UTC\"),\n", + " \"gl\": [150, 155, 160, 165],\n", + " }\n", + ")\n", "\n", "display(data)\n", "\n", - "r_result = my_check_data_columns(data,time_check=True,tz=\"Asia/Jerusalem\")\n", + "r_result = my_check_data_columns(data, time_check=True, tz=\"Asia/Jerusalem\")\n", "\n", "display(r_result)" ] diff --git a/pyproject.toml b/pyproject.toml index ada3613..aa7a4f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "iglu_python" -version = "0.2.1" +version = "0.2.4" description = "Python implementation of the iglu package for continuous glucose monitoring data analysis" readme = "README.md" requires-python = ">=3.11" @@ -26,7 +26,8 @@ classifiers = [ dependencies = [ "numpy>=2.2.6", "pandas>=2.2.3", - "tzlocal>=5.3.1" + "tzlocal>=5.3.1", + "openpyxl >= 3.1.5" ] [project.urls] @@ -90,7 +91,21 @@ disallow_incomplete_defs = false [tool.ruff] line-length = 120 target-version = "py311" -select = [ +exclude = [ + ".git/", + ".venv/", + "venv/", + "__pycache__/", + "*.egg-info/", + "build/", + "dist/", + ".pytest_cache/", + ".mypy_cache/", + ".ruff_cache/", + "tests/", + "notebooks/" +] +lint.select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes @@ -98,10 +113,10 @@ select = [ "C", # flake8-comprehensions "B", # flake8-bugbear ] -ignore = [] +lint.ignore = [] -[tool.ruff.isort] +[tool.lint.isort] known-first-party = ["iglu_python"] -[tool.ruff.per-file-ignores] +[tool.lint.per-file-ignores] "tests/*" = ["E501"] # Allow long lines in tests diff --git a/requirements.txt b/requirements.txt index 4c4217a..1855f87 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ pandas >= 2.2.3 numpy >= 2.2.6 -scipy >= 1.15.0 -tzlocal >= 5.3.1 \ No newline at end of file +tzlocal >= 5.3.1 +openpyxl >= 3.1.5 \ No newline at end of file diff --git a/tests/data/dexcom_eur_01.xlsx b/tests/data/dexcom_eur_01.xlsx new file mode 100644 index 0000000..54b67b8 Binary files /dev/null and b/tests/data/dexcom_eur_01.xlsx differ diff --git a/tests/data/dexcom_eur_02.xlsx b/tests/data/dexcom_eur_02.xlsx new file mode 100644 index 0000000..58d4ca6 Binary files /dev/null and b/tests/data/dexcom_eur_02.xlsx differ diff --git a/tests/data/dexcom_eur_03.xlsx b/tests/data/dexcom_eur_03.xlsx new file mode 100644 index 0000000..501c049 Binary files /dev/null and b/tests/data/dexcom_eur_03.xlsx differ diff --git a/tests/data/libre_amer_01.csv b/tests/data/libre_amer_01.csv new file mode 100644 index 0000000..df6e785 --- /dev/null +++ b/tests/data/libre_amer_01.csv @@ -0,0 +1,1342 @@ +Patient report,Generated on,04-26-2021 05:25 PM UTC,Generated by,xxxx,,,,,,,,,,,,,, +xxxx,xxxx,,,,,,,,,,,,,,,,, +Device,Serial Number,Device Timestamp,Record Type,Historic Glucose mg/dL,Scan Glucose mg/dL,Non-numeric Rapid-Acting Insulin,Rapid-Acting Insulin (units),Non-numeric Food,Carbohydrates (grams),Carbohydrates (servings),Non-numeric Long-Acting Insulin,Long-Acting Insulin (units),Notes,Strip Glucose mg/dL,Ketone mmol/L,Meal Insulin (units),Correction Insulin (units),User Change Insulin (units) +FreeStyle Libre Pro,xxxx,03-20-2021 05:38 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 05:53 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 06:08 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 06:23 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 06:38 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 06:53 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 07:08 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 07:23 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 07:38 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 07:53 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 08:08 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 08:23 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 08:38 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 08:53 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 09:08 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 09:23 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 09:38 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 09:53 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 10:08 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 10:23 PM,0,204,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 10:38 PM,0,201,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 10:53 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 11:08 PM,0,199,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 11:23 PM,0,205,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 11:38 PM,0,199,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-20-2021 11:53 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:08 AM,0,188,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:23 AM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:38 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:53 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:08 AM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:23 AM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:38 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:53 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:08 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:23 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:38 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:53 AM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:08 AM,0,78,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:23 AM,0,75,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:38 AM,0,72,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:53 AM,0,74,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:08 AM,0,75,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:23 AM,0,73,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:38 AM,0,72,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:53 AM,0,75,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:08 AM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:23 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:38 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:53 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:08 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:23 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:38 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:53 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:23 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:38 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:53 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:08 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:23 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:38 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:53 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:08 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:23 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:38 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:53 AM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:08 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:23 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:38 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:53 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:08 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:38 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:53 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:08 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:23 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:38 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 12:53 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:08 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:23 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:38 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 01:53 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:08 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:23 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:38 PM,0,207,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 02:53 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:08 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:23 PM,0,181,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:38 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 03:53 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:08 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:23 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:38 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 04:53 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:08 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:23 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:38 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 05:53 PM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:08 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:23 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:38 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 06:53 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:08 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:23 PM,0,75,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:38 PM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 07:53 PM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:08 PM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:23 PM,0,78,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:38 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 08:53 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:08 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:23 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:38 PM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 09:53 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:08 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:23 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:38 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 10:53 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:08 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:23 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:38 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-21-2021 11:53 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:08 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:23 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:38 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:53 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:08 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:23 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:38 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:53 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:08 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:23 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:38 AM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:53 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:08 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:23 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:38 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:53 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:08 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:23 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:38 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:53 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:08 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:23 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:38 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:53 AM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:08 AM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:23 AM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:38 AM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:53 AM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:08 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:23 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:38 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:53 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:08 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:23 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:38 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:53 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:08 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:23 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:38 AM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:53 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:08 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:23 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:38 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:53 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:08 AM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:23 AM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:38 AM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:53 AM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:08 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:23 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:38 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 12:53 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:08 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:23 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:38 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 01:53 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:08 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:23 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:38 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 02:53 PM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:08 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:23 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:38 PM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 03:53 PM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:08 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:23 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:38 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 04:53 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:08 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:23 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:38 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 05:53 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:08 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:23 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:38 PM,0,211,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 06:53 PM,0,223,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:08 PM,0,227,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:23 PM,0,222,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:38 PM,0,218,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 07:53 PM,0,206,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:08 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:23 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:38 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 08:53 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:08 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:23 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:38 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 09:53 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:08 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:23 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:38 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 10:53 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:08 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:23 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:38 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-22-2021 11:53 PM,0,187,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:08 AM,0,206,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:23 AM,0,206,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:38 AM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:53 AM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:08 AM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:23 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:38 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:53 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:08 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:23 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:38 AM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:53 AM,0,78,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:08 AM,0,73,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:23 AM,0,71,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:38 AM,0,72,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:53 AM,0,73,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:08 AM,0,72,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:23 AM,0,71,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:38 AM,0,71,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:53 AM,0,71,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:08 AM,0,71,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:23 AM,0,72,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:38 AM,0,73,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:53 AM,0,73,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:08 AM,0,74,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:23 AM,0,75,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:38 AM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:53 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:08 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:23 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:38 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:53 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:08 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:23 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:38 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:53 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:23 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:38 AM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:53 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:08 AM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:23 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:38 AM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:53 AM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:08 AM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:23 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:38 AM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:53 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:08 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:23 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:38 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:53 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:08 PM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:23 PM,0,76,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:38 PM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:53 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:08 PM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:23 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:38 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:53 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:08 PM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:23 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:38 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:53 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:08 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:23 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:38 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:53 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:08 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:23 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:38 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:53 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:08 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:23 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:38 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:53 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:08 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:23 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:38 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:53 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:08 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:23 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:38 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:53 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:08 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:23 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:38 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:53 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:08 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:23 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:38 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:53 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:08 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:23 PM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:38 PM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:53 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:08 AM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:23 AM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:38 AM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:53 AM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:08 AM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:23 AM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:38 AM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:53 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:08 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:23 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:38 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:53 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:08 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:23 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:38 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:53 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:08 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:23 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:38 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:53 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:08 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:23 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:38 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:53 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:08 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:23 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:38 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:53 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:08 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:23 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:38 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:53 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:08 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:23 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:38 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:53 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:08 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:23 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:38 AM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:53 AM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:08 AM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:23 AM,0,182,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:38 AM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:53 AM,0,184,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:08 AM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:23 AM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:38 AM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:53 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:08 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:23 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:38 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:53 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:08 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:23 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:38 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:53 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:08 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:23 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:38 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:53 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:08 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:23 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:38 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:53 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:08 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:23 PM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:38 PM,0,184,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:53 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:08 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:23 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:38 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:53 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:08 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:23 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:38 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:53 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:08 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:23 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:38 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:53 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:08 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:23 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:38 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:53 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:08 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:23 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:38 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:53 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:08 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:23 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:38 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:53 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:08 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:23 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:38 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:53 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:08 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:23 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:38 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:53 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:08 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:23 AM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:38 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:53 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:08 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:23 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:38 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:53 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:08 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:23 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:38 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:53 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:08 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:23 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:38 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:53 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:08 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:23 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:38 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:53 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:08 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:23 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:38 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:53 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:08 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:23 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:38 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:53 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:08 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:23 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:38 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:53 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:08 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:38 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:08 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:23 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:38 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:53 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:08 AM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:23 AM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:38 AM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:53 AM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:08 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:23 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:38 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:53 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:08 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:23 PM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:38 PM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:53 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:08 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:23 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:38 PM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:53 PM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:08 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:23 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:38 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:53 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:08 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:23 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:38 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:53 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:08 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:23 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:38 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:53 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:08 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:23 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:38 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:53 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:08 PM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:23 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:38 PM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:53 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:08 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:23 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:38 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:53 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:08 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:23 PM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:38 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:53 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:08 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:23 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:38 PM,0,184,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:53 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:08 PM,0,194,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:23 PM,0,191,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:38 PM,0,186,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:53 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:08 AM,0,181,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:23 AM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:38 AM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:53 AM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:08 AM,0,172,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:23 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:38 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:53 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:08 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:23 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:38 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:53 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:08 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:23 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:38 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:53 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:08 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:23 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:38 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:53 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:08 AM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:23 AM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:38 AM,0,76,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:53 AM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:08 AM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:23 AM,0,78,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:38 AM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:53 AM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:08 AM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:23 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:38 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:53 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:08 AM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:23 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:38 AM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:53 AM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:08 AM,0,78,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:23 AM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:38 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:53 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:08 AM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:23 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:38 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:53 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:08 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:23 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:38 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:53 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:08 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:23 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:38 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:53 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:08 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:23 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:38 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:53 PM,0,181,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:08 PM,0,210,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:23 PM,0,209,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:38 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:53 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:08 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:23 PM,0,181,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:38 PM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:53 PM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:08 PM,0,172,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:23 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:38 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:53 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:08 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:23 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:38 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:53 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:08 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:23 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:38 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:53 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:08 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:23 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:38 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:53 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:08 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:23 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:38 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:53 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:08 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:23 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:38 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:53 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:08 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:23 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:38 PM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:53 PM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:08 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:23 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:38 PM,0,196,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:53 PM,0,202,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:08 AM,0,207,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:23 AM,0,210,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:38 AM,0,209,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:53 AM,0,210,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:08 AM,0,213,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:23 AM,0,213,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:38 AM,0,218,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:53 AM,0,224,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:08 AM,0,223,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:23 AM,0,214,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:38 AM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:53 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:08 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:23 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:38 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:53 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:08 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:38 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:53 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:08 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:23 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:38 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:53 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:08 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:23 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:38 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:53 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:08 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:23 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:38 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:53 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:08 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:23 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:38 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:53 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:08 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:23 AM,0,88,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:38 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:53 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:08 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:23 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:38 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:53 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:08 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:23 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:38 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:53 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:08 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:23 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:38 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:53 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:08 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:23 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:38 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:53 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:08 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:23 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:38 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:53 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:08 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:23 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:38 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:53 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:08 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:23 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:38 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:53 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:08 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:23 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:38 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:53 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:08 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:23 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:38 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:53 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:08 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:23 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:38 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:53 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:08 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:23 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:38 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:53 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:08 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:23 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:38 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:53 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:08 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:23 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:38 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:53 PM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:08 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:23 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:38 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:53 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:08 AM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:23 AM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:38 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:53 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:08 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:23 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:38 AM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:53 AM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:08 AM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:23 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:38 AM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:53 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:08 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:23 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:38 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:53 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:08 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:23 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:38 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:53 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:08 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:38 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:53 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:23 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:38 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:08 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:23 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:38 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:53 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:08 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:23 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:38 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:53 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:08 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:23 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:38 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:53 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:08 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:23 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:38 AM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:53 AM,0,194,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:08 AM,0,223,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:23 AM,0,234,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:38 AM,0,225,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:53 AM,0,206,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:08 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:23 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:38 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:53 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:08 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:23 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:38 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:53 PM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:08 PM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:23 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:38 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:53 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:08 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:23 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:38 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:53 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:08 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:23 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:38 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:53 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:08 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:23 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:38 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:53 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:08 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:23 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:38 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:53 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:08 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:23 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:38 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:53 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:08 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:23 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:38 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:53 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:08 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:23 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:38 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:53 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:08 PM,0,186,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:23 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:38 PM,0,182,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:53 PM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:08 PM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:23 PM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:38 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:53 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:08 AM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:23 AM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:38 AM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:53 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:08 AM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:23 AM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:38 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:53 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:08 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:23 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:38 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:53 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:08 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:23 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:38 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:53 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:38 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:53 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:23 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:38 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:53 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:23 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:38 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:53 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:08 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:23 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:38 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:53 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:08 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:23 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:38 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:53 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:08 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:23 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:38 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:53 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:08 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:23 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:38 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:53 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:08 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:23 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:38 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:53 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:08 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:23 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:38 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:53 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:08 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:23 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:38 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:53 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:08 PM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:23 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:38 PM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:53 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:08 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:23 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:38 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:53 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:08 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:23 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:38 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:53 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:08 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:23 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:38 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:53 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:08 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:23 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:38 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:53 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:08 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:23 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:38 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:53 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:08 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:23 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:38 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:53 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:08 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:23 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:38 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:53 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:08 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:23 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:38 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:53 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:08 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:23 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:38 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:53 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:08 AM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:23 AM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:38 AM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:53 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:08 AM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:23 AM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:38 AM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:53 AM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:08 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:23 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:38 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:53 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:08 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:23 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:38 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:53 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:23 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:38 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:38 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:53 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:08 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:23 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:38 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:53 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:08 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:23 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:38 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:53 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:08 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:23 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:38 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:53 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:08 AM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:23 AM,0,188,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:38 AM,0,202,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:53 AM,0,207,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:08 AM,0,206,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:23 AM,0,198,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:38 AM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:53 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:08 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:23 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:38 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:53 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:08 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:23 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:38 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:53 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:08 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:23 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:38 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:53 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:08 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:23 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:38 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:53 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:08 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:23 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:38 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:53 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:08 PM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:23 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:38 PM,0,80,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:53 PM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:08 PM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:23 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:38 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:53 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:08 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:23 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:38 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:53 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:08 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:23 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:38 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:53 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:08 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:23 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:38 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:53 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:08 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:23 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:38 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:53 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:08 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:23 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:38 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:53 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:08 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:23 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:38 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:53 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:08 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:23 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:38 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:53 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:08 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:23 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:38 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:53 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:08 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:23 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:38 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:53 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:08 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:23 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:38 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:53 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:08 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:23 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:38 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:53 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:08 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:23 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:38 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:53 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:08 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:23 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:38 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:53 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:08 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:23 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:38 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:53 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:08 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:23 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:38 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:53 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:08 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:23 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:38 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:53 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:08 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:23 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:38 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:53 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:08 AM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:23 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:38 AM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:53 AM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:08 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:23 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:38 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:53 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:08 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:23 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:38 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:53 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:08 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:23 PM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:38 PM,0,205,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:53 PM,0,227,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:08 PM,0,232,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:23 PM,0,229,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:38 PM,0,223,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:53 PM,0,213,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:08 PM,0,208,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:23 PM,0,202,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:38 PM,0,193,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:53 PM,0,187,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:08 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:23 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:38 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:53 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:08 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:23 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:38 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:53 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:08 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:23 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:38 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:53 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:08 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:23 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:38 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:53 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:08 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:23 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:38 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:53 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:08 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:23 PM,0,172,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:38 PM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:53 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:08 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:23 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:38 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:53 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:08 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:23 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:38 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:53 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:08 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:23 AM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:38 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:53 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:23 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:38 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:53 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:08 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:23 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:38 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:53 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:08 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:23 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:38 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:53 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:08 AM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:23 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:38 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:53 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:08 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:23 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:38 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:53 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:08 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:23 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:38 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:53 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:23 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:38 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:53 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:08 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:23 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:38 AM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:53 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:08 AM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:23 AM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:38 AM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:53 AM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:08 AM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:23 AM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:38 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:53 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:08 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:23 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:38 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:53 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:08 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:23 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:38 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:53 PM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:08 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:23 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:38 PM,0,79,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:53 PM,0,77,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:08 PM,0,78,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:23 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:38 PM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:53 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:08 PM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:23 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:38 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:53 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:08 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:23 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:38 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:53 PM,0,172,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:08 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:23 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:38 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:53 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:08 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:23 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:38 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:53 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:08 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:23 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:38 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:53 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:08 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:23 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:38 PM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:53 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:08 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:23 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:38 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:53 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:08 PM,0,187,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:23 PM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:38 PM,0,186,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:53 PM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:08 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:23 AM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:38 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:53 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:08 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:23 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:38 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:53 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:08 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:23 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:38 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:08 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:23 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:38 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:53 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:08 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:23 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:38 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:53 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:08 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:23 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:38 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:53 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:23 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:38 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:53 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:23 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:38 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:53 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:08 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:23 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:38 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:53 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:08 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:23 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:38 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:53 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:08 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:23 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:38 AM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:53 AM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:08 AM,0,181,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:23 AM,0,199,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:38 AM,0,202,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:53 AM,0,188,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:08 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:23 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:38 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:53 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:08 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:23 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:38 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:53 PM,0,86,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:08 PM,0,72,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:23 PM,0,63,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:38 PM,0,59,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:53 PM,0,58,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:08 PM,0,64,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:23 PM,0,74,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:38 PM,0,82,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:53 PM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:08 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:23 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:38 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:53 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:08 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:23 PM,0,187,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:38 PM,0,195,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:53 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:08 PM,0,210,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:23 PM,0,222,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:38 PM,0,224,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:53 PM,0,221,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:08 PM,0,213,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:23 PM,0,207,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:38 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:53 PM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:08 PM,0,188,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:23 PM,0,190,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:38 PM,0,191,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:53 PM,0,197,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:08 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:23 PM,0,199,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:38 PM,0,199,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:53 PM,0,200,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:08 PM,0,209,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:23 PM,0,221,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:38 PM,0,223,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:53 PM,0,221,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:08 PM,0,220,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:23 PM,0,225,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:38 PM,0,232,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:53 PM,0,237,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:08 AM,0,234,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:23 AM,0,225,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:38 AM,0,214,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:53 AM,0,209,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:08 AM,0,197,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:23 AM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:38 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:53 AM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:08 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:23 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:38 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:53 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:08 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:23 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:38 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:53 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:23 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:38 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:23 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:38 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:08 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:23 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:38 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:53 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:08 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:23 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:38 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:53 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:08 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:23 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:38 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:53 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:08 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:23 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:38 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:53 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:08 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:23 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:38 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:53 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:08 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:23 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:38 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:53 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:08 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:23 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:38 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:53 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:08 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:23 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:38 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:53 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:08 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:23 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:38 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:53 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:08 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:23 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:38 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:53 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:08 PM,0,110,,,,,,,,,,,,,, diff --git a/tests/data/libre_amer_02.csv b/tests/data/libre_amer_02.csv new file mode 100644 index 0000000..5b8ffc2 --- /dev/null +++ b/tests/data/libre_amer_02.csv @@ -0,0 +1,1341 @@ +Patient report,Generated on,04-26-2021 04:41 PM UTC,Generated by,xxxx,,,,,,,,,,,,,, +xxxx,xxxx,,,,,,,,,,,,,,,,, +Device,Serial Number,Device Timestamp,Record Type,Historic Glucose mg/dL,Scan Glucose mg/dL,Non-numeric Rapid-Acting Insulin,Rapid-Acting Insulin (units),Non-numeric Food,Carbohydrates (grams),Carbohydrates (servings),Non-numeric Long-Acting Insulin,Long-Acting Insulin (units),Notes,Strip Glucose mg/dL,Ketone mmol/L,Meal Insulin (units),Correction Insulin (units),User Change Insulin (units) +FreeStyle Libre Pro,xxxx,03-23-2021 03:26 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:41 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:56 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:11 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:26 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:41 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:56 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:11 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:26 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:41 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:56 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:11 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:26 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:41 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:56 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:11 AM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:26 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:41 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:11 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:26 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:41 AM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:56 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:11 AM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:26 AM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:41 AM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:56 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:11 AM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:26 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:41 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:56 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:11 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:11 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:26 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:41 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 12:56 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:11 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:26 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:41 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 01:56 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:11 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:26 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:41 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 02:56 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:11 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:26 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:41 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 03:56 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:11 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:26 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:41 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 04:56 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:11 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:26 PM,0,187,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:41 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 05:56 PM,0,201,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:11 PM,0,207,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:26 PM,0,201,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:41 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 06:56 PM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:11 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:26 PM,0,193,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:41 PM,0,203,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 07:56 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:11 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:26 PM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:41 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 08:56 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:11 PM,0,172,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:26 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:41 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 09:56 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:11 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:26 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 10:56 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:11 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:26 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:41 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-23-2021 11:56 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:11 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:26 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:56 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:11 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:26 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:41 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:56 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:11 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:26 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:41 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:56 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:11 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:26 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:41 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:56 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:11 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:26 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:41 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:56 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:11 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:26 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:41 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:56 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:11 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:26 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:41 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:11 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:26 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:41 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:56 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:11 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:26 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:41 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:56 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:11 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:41 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:11 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:26 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:41 AM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:56 AM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:11 AM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:26 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:41 AM,0,182,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:56 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:11 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:26 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:41 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 12:56 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:11 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:26 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:41 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 01:56 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:11 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:26 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:41 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 02:56 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:11 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:26 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:41 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 03:56 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:11 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:26 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:41 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 04:56 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:11 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:26 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:41 PM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 05:56 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:11 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:26 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:41 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 06:56 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:11 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:26 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:41 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 07:56 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:11 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:26 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:41 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 08:56 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:11 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:26 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:41 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 09:56 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:11 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:26 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:41 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 10:56 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:11 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:26 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-24-2021 11:56 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:11 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:26 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:41 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:11 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:26 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:11 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:26 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:41 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:56 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:11 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:41 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:56 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:11 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:56 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:11 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:41 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:26 AM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:41 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:56 AM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:11 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:26 AM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:41 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:56 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:26 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:41 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:56 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:11 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:26 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:41 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:56 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:11 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:26 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:41 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:56 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:11 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:26 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:41 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:56 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:11 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:41 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 12:56 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:11 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:26 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:41 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 01:56 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:11 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:26 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:41 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 02:56 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:11 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:26 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:41 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 03:56 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:11 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:26 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:41 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 04:56 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:11 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:26 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:41 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 05:56 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:11 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:26 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:41 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 06:56 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:11 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:26 PM,0,186,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:41 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 07:56 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:11 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:26 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:41 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 08:56 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:11 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:26 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:41 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 09:56 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:11 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:26 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:41 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 10:56 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:11 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:26 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:41 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-25-2021 11:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:11 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:26 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:41 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:56 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:11 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:26 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:41 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:56 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:41 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:56 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:11 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:26 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:41 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:56 AM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:11 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:26 AM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:41 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:56 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:11 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:26 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:56 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:11 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:26 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:41 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:56 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:11 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:26 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:41 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:11 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:26 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:41 AM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:56 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:26 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:41 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:56 AM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:11 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:26 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:41 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:56 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:41 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:56 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:11 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:26 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:41 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 12:56 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:11 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:26 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:41 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 01:56 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:11 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:26 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:41 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 02:56 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:11 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:26 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:41 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 03:56 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:11 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:26 PM,0,190,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:41 PM,0,204,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 04:56 PM,0,213,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:11 PM,0,218,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:26 PM,0,217,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:41 PM,0,211,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 05:56 PM,0,196,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:11 PM,0,191,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:26 PM,0,194,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:41 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 06:56 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:11 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:26 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:41 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 07:56 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:11 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:26 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:41 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 08:56 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:11 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:41 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 09:56 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:11 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:26 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:41 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 10:56 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:11 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:26 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:41 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-26-2021 11:56 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:11 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:26 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:11 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:26 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:41 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:11 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:56 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:26 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:41 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:56 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:11 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:41 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:56 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:11 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:26 AM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:41 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:56 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:11 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:26 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:56 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:11 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:26 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:41 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:56 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:11 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:26 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:41 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:56 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:11 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:26 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:56 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:11 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:26 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:41 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:56 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:11 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:26 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:41 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:56 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:11 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:26 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 12:56 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:11 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:26 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:41 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 01:56 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:11 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:26 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:41 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 02:56 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:11 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:26 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:41 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 03:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:11 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:26 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:41 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 04:56 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:11 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:26 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:41 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 05:56 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:11 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:26 PM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:41 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 06:56 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:11 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:26 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:41 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 07:56 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:11 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:26 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:41 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 08:56 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:11 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:26 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:41 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 09:56 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:11 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:26 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:41 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 10:56 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:11 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:26 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:41 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-27-2021 11:56 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:11 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:26 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:41 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:56 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:11 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:26 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:41 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:11 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:41 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:56 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:11 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:41 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:41 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:56 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:11 AM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:26 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:41 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:56 AM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:11 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:41 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:56 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:11 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:41 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:11 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:26 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:56 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:11 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:26 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:41 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:56 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:11 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:26 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:56 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:41 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:56 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:11 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:26 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:41 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 12:56 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:11 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:26 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:41 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 01:56 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:11 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:26 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:41 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 02:56 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:11 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:26 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:41 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 03:56 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:11 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:26 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:41 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 04:56 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:11 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:26 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:41 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 05:56 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:11 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:26 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:41 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 06:56 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:11 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:26 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:41 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 07:56 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:11 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:26 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:41 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 08:56 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:11 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:26 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:41 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 09:56 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:11 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:26 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:41 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 10:56 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:11 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:26 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:41 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-28-2021 11:56 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:11 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:26 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:41 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:11 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:11 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:26 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:41 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:56 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:11 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:26 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:41 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:56 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:11 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:26 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:56 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:11 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:26 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:41 AM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:56 AM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:11 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:11 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:41 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:56 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:11 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:26 AM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:41 AM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:56 AM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:11 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:26 AM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:41 AM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:56 AM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:11 AM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:26 AM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:41 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:56 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:11 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:26 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:41 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:56 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:11 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:26 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:41 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 12:56 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:11 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:26 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:41 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 01:56 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:11 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:26 PM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:41 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 02:56 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:11 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:26 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:41 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 03:56 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:11 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:26 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:41 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 04:56 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:11 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:26 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:41 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 05:56 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:11 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:26 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:41 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 06:56 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:11 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:26 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:41 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 07:56 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:11 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:26 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:41 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 08:56 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:11 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:26 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:41 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 09:56 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:11 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:26 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:41 PM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 10:56 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:11 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:26 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:41 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-29-2021 11:56 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:11 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:56 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:41 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:56 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:11 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:41 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:11 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:26 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:41 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:56 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:11 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:26 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:41 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:26 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:41 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:56 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:11 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:26 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:41 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:56 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:11 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:26 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:56 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:11 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:41 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:26 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:41 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:56 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:11 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:26 AM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:41 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:26 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:41 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:56 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:11 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:26 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:41 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 12:56 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:11 PM,0,184,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:26 PM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:41 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 01:56 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:11 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:26 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:41 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 02:56 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:11 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:26 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:41 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 03:56 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:11 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:26 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:41 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 04:56 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:11 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:26 PM,0,161,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:41 PM,0,168,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 05:56 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:11 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:26 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:41 PM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 06:56 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:11 PM,0,171,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:26 PM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:41 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 07:56 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:11 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:26 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:41 PM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 08:56 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:11 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:26 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:41 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 09:56 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:11 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:26 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:41 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 10:56 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:11 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:26 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:41 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-30-2021 11:56 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:11 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:26 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:41 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:56 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:11 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:26 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:56 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:11 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:11 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:26 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:41 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:56 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:11 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:26 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:41 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:56 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:11 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:26 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:41 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:56 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:41 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:56 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:11 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:26 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:41 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:56 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:11 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:26 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:41 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:56 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:11 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:26 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:56 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:11 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:26 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:41 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:26 AM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:41 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:56 AM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:11 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:26 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:41 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 12:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:11 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:26 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:41 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 01:56 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:11 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:26 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:41 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 02:56 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:11 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:26 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:41 PM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 03:56 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:11 PM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:26 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:41 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 04:56 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:11 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:26 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:41 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 05:56 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:11 PM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:26 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:41 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 06:56 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:11 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:26 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:41 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 07:56 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:11 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:26 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:41 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 08:56 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:11 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:26 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:41 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 09:56 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:11 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 10:56 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:11 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:26 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:41 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,03-31-2021 11:56 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:11 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:26 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:11 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:41 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:56 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:11 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:26 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:41 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:56 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:11 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:26 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:41 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:56 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:11 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:26 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:41 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:56 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:11 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:26 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:56 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:11 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:26 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:41 AM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:56 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:11 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:26 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:41 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:56 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:11 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:26 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:41 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:56 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:11 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:26 AM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:41 AM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:56 AM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:11 AM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:26 AM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:41 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:56 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:11 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:26 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:41 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 12:56 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:11 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:26 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:41 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 01:56 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:11 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:26 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:41 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 02:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:11 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:26 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:41 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 03:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:11 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:41 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 04:56 PM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:11 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:26 PM,0,170,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:41 PM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 05:56 PM,0,186,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:11 PM,0,197,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:26 PM,0,208,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:41 PM,0,215,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 06:56 PM,0,217,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:11 PM,0,207,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:26 PM,0,192,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:41 PM,0,195,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 07:56 PM,0,218,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:11 PM,0,232,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:26 PM,0,223,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:41 PM,0,205,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 08:56 PM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:11 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:26 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:41 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 09:56 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:11 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:26 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:41 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 10:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:11 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:26 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:41 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-01-2021 11:56 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:11 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:41 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:56 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:11 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:41 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:56 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:41 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:56 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:11 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:26 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:11 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:26 AM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:41 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:56 AM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:11 AM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:26 AM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:41 AM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:56 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:26 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:41 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:56 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:11 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:26 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:41 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:56 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:11 AM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:26 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:41 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:56 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:11 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:26 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:41 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:56 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:11 AM,0,89,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:26 AM,0,90,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:41 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:11 PM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:26 PM,0,87,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:41 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 12:56 PM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:11 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:26 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:41 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 01:56 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:11 PM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:26 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:41 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 02:56 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:11 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:26 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:41 PM,0,164,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 03:56 PM,0,182,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:11 PM,0,197,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:26 PM,0,195,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:41 PM,0,181,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 04:56 PM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:11 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:26 PM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:41 PM,0,178,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 05:56 PM,0,179,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:11 PM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:26 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:41 PM,0,185,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 06:56 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:11 PM,0,172,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:26 PM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:41 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 07:56 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:11 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:26 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:41 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 08:56 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:11 PM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:26 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:41 PM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 09:56 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:11 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:41 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 10:56 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:11 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:26 PM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:41 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-02-2021 11:56 PM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:11 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:26 AM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:41 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:56 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:11 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:26 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:41 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:56 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:11 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:41 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:56 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:11 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:26 AM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:41 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:56 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:11 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:26 AM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:41 AM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:56 AM,0,156,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:11 AM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:26 AM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:41 AM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:56 AM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:26 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:41 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:11 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:26 AM,0,95,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:41 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:56 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:11 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:26 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:41 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:56 AM,0,138,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:11 AM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:26 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:41 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:56 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:11 AM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:26 AM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:41 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:56 AM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:11 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:26 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:41 AM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:56 AM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:11 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:26 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 12:56 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:11 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:26 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:41 PM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 01:56 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:11 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:41 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 02:56 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:11 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:26 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:41 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 03:56 PM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:11 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:26 PM,0,136,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:41 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 04:56 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:11 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:26 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:41 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 05:56 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:11 PM,0,153,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:26 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:41 PM,0,148,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 06:56 PM,0,144,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:11 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:26 PM,0,126,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:41 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 07:56 PM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:11 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:26 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:41 PM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 08:56 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:11 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:26 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:41 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 09:56 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:11 PM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:26 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:41 PM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 10:56 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:11 PM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:26 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:41 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-03-2021 11:56 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:11 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:41 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:56 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:11 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:26 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:41 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:11 AM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:26 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:41 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:56 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:11 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:41 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:56 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:11 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:41 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:56 AM,0,113,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:11 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:26 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:41 AM,0,110,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:56 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:11 AM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:26 AM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:41 AM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:56 AM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:11 AM,0,155,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:26 AM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:41 AM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:56 AM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:11 AM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:26 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:41 AM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:56 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:11 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:26 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:41 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:56 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:11 AM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:26 AM,0,112,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:41 AM,0,117,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:56 AM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:11 AM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:26 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:41 AM,0,100,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:11 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:26 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:41 PM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 12:56 PM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:11 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:26 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:41 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 01:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:11 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:26 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:41 PM,0,129,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 02:56 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:11 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:26 PM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:41 PM,0,132,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 03:56 PM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:11 PM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:26 PM,0,151,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:41 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 04:56 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:11 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:26 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:41 PM,0,118,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 05:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:11 PM,0,115,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:26 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:41 PM,0,119,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 06:56 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:11 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:26 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:41 PM,0,166,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 07:56 PM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:11 PM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:26 PM,0,150,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:41 PM,0,145,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 08:56 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:11 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:26 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:41 PM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 09:56 PM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:11 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:26 PM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:41 PM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 10:56 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:11 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:26 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:41 PM,0,93,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-04-2021 11:56 PM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:11 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:26 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:41 AM,0,91,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:56 AM,0,94,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:11 AM,0,96,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:26 AM,0,97,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:41 AM,0,99,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:11 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:26 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:41 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:56 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:11 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:26 AM,0,102,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:41 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:56 AM,0,105,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:11 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:26 AM,0,114,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:41 AM,0,147,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:56 AM,0,184,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:11 AM,0,203,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:26 AM,0,205,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:41 AM,0,191,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:56 AM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:11 AM,0,125,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:26 AM,0,109,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:41 AM,0,103,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:56 AM,0,92,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:11 AM,0,85,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:26 AM,0,83,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:41 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:56 AM,0,81,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:11 AM,0,84,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:26 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:41 AM,0,122,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:56 AM,0,142,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:11 AM,0,163,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:26 AM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:41 AM,0,175,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:56 AM,0,177,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:11 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:26 AM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:41 AM,0,154,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:56 AM,0,152,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:11 AM,0,157,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:26 AM,0,167,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:41 AM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:56 AM,0,173,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:11 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:26 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:41 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 12:56 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:11 PM,0,130,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:26 PM,0,123,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 01:56 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:11 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:26 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:41 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 02:56 PM,0,187,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:11 PM,0,189,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:26 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:41 PM,0,176,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 03:56 PM,0,159,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:11 PM,0,146,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:26 PM,0,143,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:41 PM,0,141,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 04:56 PM,0,135,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:11 PM,0,128,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:26 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:41 PM,0,120,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 05:56 PM,0,124,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:11 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:26 PM,0,137,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:41 PM,0,133,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 06:56 PM,0,131,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:11 PM,0,139,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:26 PM,0,160,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:41 PM,0,180,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 07:56 PM,0,188,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:11 PM,0,183,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:26 PM,0,174,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:41 PM,0,169,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 08:56 PM,0,165,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:11 PM,0,162,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:26 PM,0,158,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:41 PM,0,149,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 09:56 PM,0,140,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:11 PM,0,134,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:26 PM,0,127,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:41 PM,0,121,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 10:56 PM,0,116,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:11 PM,0,111,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:26 PM,0,108,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:41 PM,0,106,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-05-2021 11:56 PM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 12:11 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 12:26 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 12:41 AM,0,98,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 12:56 AM,0,101,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 01:11 AM,0,104,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 01:26 AM,0,107,,,,,,,,,,,,,, +FreeStyle Libre Pro,xxxx,04-06-2021 01:41 AM,0,108,,,,,,,,,,,,,, diff --git a/tests/test_load_data.py b/tests/test_load_data.py new file mode 100644 index 0000000..b867654 --- /dev/null +++ b/tests/test_load_data.py @@ -0,0 +1,216 @@ +""" +Unit tests for iglu_python.extension.load_data module. + +Tests the functionality of loading CGM data from device-specific files. +""" + +import os +import tempfile +from pathlib import Path + +import numpy as np +import pandas as pd +import pytest + +# Import the module to test +from iglu_python import load_dexcom, load_libre + + +@pytest.fixture(scope="module") +def test_data_paths(): + test_data_dir = Path(__file__).parent / "data" + return { + 'libre_amer_01': test_data_dir / "libre_amer_01.csv", + 'libre_amer_02': test_data_dir / "libre_amer_02.csv", + 'dexcom_eur_01': test_data_dir / "dexcom_eur_01.xlsx", + 'dexcom_eur_02': test_data_dir / "dexcom_eur_02.xlsx", + 'dexcom_eur_03': test_data_dir / "dexcom_eur_03.xlsx", + } + +@pytest.mark.parametrize("key", [ + 'libre_amer_01', 'libre_amer_02', 'dexcom_eur_01', 'dexcom_eur_02', 'dexcom_eur_03' +]) +def test_files_exist(test_data_paths, key): + assert test_data_paths[key].exists(), f"Test file not found: {test_data_paths[key]}" + +def test_load_libre_amer_01(test_data_paths): + timeseries = load_libre(str(test_data_paths['libre_amer_01'])) + assert isinstance(timeseries, pd.Series) + assert isinstance(timeseries.index, pd.DatetimeIndex) + assert len(timeseries) > 0 + numeric_values = pd.to_numeric(timeseries, errors='coerce').dropna() + assert all(35 <= val <= 400 for val in numeric_values) + assert timeseries.index.is_monotonic_increasing + expected_first_values = [127, 124, 121, 131, 153] + actual_first_values = pd.to_numeric(timeseries.head(), errors='coerce').dropna().tolist() + np.testing.assert_array_almost_equal(actual_first_values, expected_first_values, decimal=0) + +def test_load_libre_amer_02(test_data_paths): + timeseries = load_libre(str(test_data_paths['libre_amer_02'])) + assert isinstance(timeseries, pd.Series) + assert isinstance(timeseries.index, pd.DatetimeIndex) + assert len(timeseries) > 0 + numeric_values = pd.to_numeric(timeseries, errors='coerce').dropna() + assert all(35 <= val <= 400 for val in numeric_values) + assert timeseries.index.is_monotonic_increasing + expected_first_values = [118, 120, 128, 137, 132] + actual_first_values = pd.to_numeric(timeseries.head(), errors='coerce').dropna().tolist() + np.testing.assert_array_almost_equal(actual_first_values, expected_first_values, decimal=0) + +def test_load_libre_data_consistency(test_data_paths): + ts1 = load_libre(str(test_data_paths['libre_amer_01'])) + ts2 = load_libre(str(test_data_paths['libre_amer_02'])) + assert isinstance(ts1, pd.Series) + assert isinstance(ts2, pd.Series) + assert isinstance(ts1.index, pd.DatetimeIndex) + assert isinstance(ts2.index, pd.DatetimeIndex) + numeric_1 = pd.to_numeric(ts1, errors='coerce').dropna() + numeric_2 = pd.to_numeric(ts2, errors='coerce').dropna() + assert all(35 <= val <= 400 for val in numeric_1) + assert all(35 <= val <= 400 for val in numeric_2) + +def test_load_libre_time_format(test_data_paths): + timeseries = load_libre(str(test_data_paths['libre_amer_01'])) + sample_times = timeseries.index[:5] + assert all(time.year == 2021 for time in sample_times) + assert all(time.month == 3 for time in sample_times) + +def test_load_libre_no_nan_values(test_data_paths): + ts1 = load_libre(str(test_data_paths['libre_amer_01'])) + ts2 = load_libre(str(test_data_paths['libre_amer_02'])) + assert not ts1.isna().any() + assert not ts2.isna().any() + +def test_load_dexcom_eur_01(test_data_paths): + timeseries = load_dexcom(str(test_data_paths['dexcom_eur_01'])) + assert isinstance(timeseries, pd.Series) + assert isinstance(timeseries.index, pd.DatetimeIndex) + assert len(timeseries) > 0 + # Convert to numeric and check values are reasonable glucose values (mg/dL) + numeric_values = pd.to_numeric(timeseries, errors='coerce').dropna() + assert all(35 <= val <= 400 for val in numeric_values) + assert timeseries.index.is_monotonic_increasing + +def test_load_dexcom_eur_02(test_data_paths): + timeseries = load_dexcom(str(test_data_paths['dexcom_eur_02'])) + assert isinstance(timeseries, pd.Series) + assert isinstance(timeseries.index, pd.DatetimeIndex) + assert len(timeseries) > 0 + # Convert to numeric and check values are reasonable glucose values (mg/dL) + numeric_values = pd.to_numeric(timeseries, errors='coerce').dropna() + assert all(35 <= val <= 400 for val in numeric_values) + assert timeseries.index.is_monotonic_increasing + +def test_load_dexcom_eur_03(test_data_paths): + timeseries = load_dexcom(str(test_data_paths['dexcom_eur_03'])) + assert isinstance(timeseries, pd.Series) + assert isinstance(timeseries.index, pd.DatetimeIndex) + assert len(timeseries) > 0 + # Convert to numeric and check values are reasonable glucose values (mg/dL) + numeric_values = pd.to_numeric(timeseries, errors='coerce').dropna() + assert all(35 <= val <= 400 for val in numeric_values) + assert timeseries.index.is_monotonic_increasing + +def test_load_dexcom_data_consistency(test_data_paths): + ts_01 = load_dexcom(str(test_data_paths['dexcom_eur_01'])) + ts_02 = load_dexcom(str(test_data_paths['dexcom_eur_02'])) + ts_03 = load_dexcom(str(test_data_paths['dexcom_eur_03'])) + # All should have the same structure + assert isinstance(ts_01, pd.Series) + assert isinstance(ts_02, pd.Series) + assert isinstance(ts_03, pd.Series) + assert isinstance(ts_01.index, pd.DatetimeIndex) + assert isinstance(ts_02.index, pd.DatetimeIndex) + assert isinstance(ts_03.index, pd.DatetimeIndex) + # All should have glucose data + for ts in [ts_01, ts_02, ts_03]: + numeric_values = pd.to_numeric(ts, errors='coerce').dropna() + assert len(numeric_values) > 0 + +def test_load_dexcom_timestamp_format(test_data_paths): + timeseries = load_dexcom(str(test_data_paths['dexcom_eur_01'])) + # Check that timestamps are in the expected format + sample_times = timeseries.index[:5] + # Check that all times are in 2023 (from the test data) + assert all(time.year == 2023 for time in sample_times) + +def test_load_dexcom_glucose_statistics(test_data_paths): + ts_01 = load_dexcom(str(test_data_paths['dexcom_eur_01'])) + ts_02 = load_dexcom(str(test_data_paths['dexcom_eur_02'])) + ts_03 = load_dexcom(str(test_data_paths['dexcom_eur_03'])) + + for ts in [ts_01, ts_02, ts_03]: + # Convert to numeric for statistics + numeric_values = pd.to_numeric(ts, errors='coerce').dropna() + assert len(numeric_values) > 0 + assert numeric_values.mean() > 0 + assert numeric_values.std() > 0 + # Check that means are reasonable glucose values (mg/dL) + assert 80 <= numeric_values.mean() <= 300 + +def test_load_libre_error_handling(): + with pytest.raises(FileNotFoundError): + load_libre("nonexistent_file.csv") + with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as tmp_file: + tmp_file_path = tmp_file.name + try: + with pytest.raises(Exception): + load_libre(tmp_file_path) + finally: + os.unlink(tmp_file_path) + +def test_load_dexcom_error_handling(): + with pytest.raises(FileNotFoundError): + load_dexcom("nonexistent_file.xlsx") + with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as tmp_file: + tmp_file_path = tmp_file.name + try: + with pytest.raises(Exception): + load_dexcom(tmp_file_path) + finally: + os.unlink(tmp_file_path) + +def test_load_libre_data_statistics(test_data_paths): + ts1 = load_libre(str(test_data_paths['libre_amer_01'])) + ts2 = load_libre(str(test_data_paths['libre_amer_02'])) + numeric_1 = pd.to_numeric(ts1, errors='coerce') + numeric_2 = pd.to_numeric(ts2, errors='coerce') + assert numeric_1.mean() > 0 + assert numeric_2.mean() > 0 + assert numeric_1.std() > 0 + assert numeric_2.std() > 0 + assert 80 <= numeric_1.mean() <= 200 + assert 80 <= numeric_2.mean() <= 200 + +def test_load_libre_time_interval(test_data_paths): + timeseries = load_libre(str(test_data_paths['libre_amer_01'])) + time_diffs = timeseries.index.to_series().diff().dropna() + expected_interval = pd.Timedelta(minutes=15) + tolerance = pd.Timedelta(minutes=5) + close_intervals = time_diffs[abs(time_diffs - expected_interval) <= tolerance] + assert len(close_intervals) / len(time_diffs) > 0.8 # At least 80% should be close + +def test_load_dexcom_time_interval(test_data_paths): + timeseries = load_dexcom(str(test_data_paths['dexcom_eur_01'])) + time_diffs = timeseries.index.to_series().diff().dropna() + # Most intervals should be around 5 minutes (300 seconds) + # Allow some tolerance for missing data points + expected_interval = pd.Timedelta(minutes=5) + tolerance = pd.Timedelta(minutes=2) # Allow some variation + # Check that most intervals are close to expected + close_intervals = time_diffs[abs(time_diffs - expected_interval) <= tolerance] + assert len(close_intervals) / len(time_diffs) > 0.8 # At least 80% should be close + +def test_load_libre_numeric_values(test_data_paths): + timeseries = load_libre(str(test_data_paths['libre_amer_01'])) + # Check that all values are numeric + assert pd.api.types.is_numeric_dtype(timeseries) + # Check that there are no NaN values (all should be valid numbers) + assert not timeseries.isna().any() + +def test_load_dexcom_numeric_values(test_data_paths): + timeseries = load_dexcom(str(test_data_paths['dexcom_eur_01'])) + # Check that all values are numeric + assert pd.api.types.is_numeric_dtype(timeseries) + # Check that there are no NaN values (all should be valid numbers) + assert not timeseries.isna().any()