UNPKG

@sports-alliance/sports-lib

Version:

A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc

481 lines (480 loc) 30.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventImporterTCX = void 0; const event_1 = require("../../../event"); const activity_1 = require("../../../../activities/activity"); const creator_1 = require("../../../../creators/creator"); const lap_1 = require("../../../../laps/lap"); const data_energy_1 = require("../../../../data/data.energy"); const data_duration_1 = require("../../../../data/data.duration"); const data_elapsed_time_1 = require("../../../../data/data.elapsed-time"); const data_distance_1 = require("../../../../data/data.distance"); const data_pause_1 = require("../../../../data/data.pause"); const data_speed_max_1 = require("../../../../data/data.speed-max"); const data_heart_rate_avg_1 = require("../../../../data/data.heart-rate-avg"); const data_heart_rate_max_1 = require("../../../../data/data.heart-rate-max"); const activity_types_1 = require("../../../../activities/activity.types"); const data_speed_avg_1 = require("../../../../data/data.speed-avg"); const lap_types_1 = require("../../../../laps/lap.types"); const importer_suunto_device_names_1 = require("../suunto/importer.suunto.device.names"); const importer_tcx_mapper_1 = require("./importer.tcx.mapper"); const event_utilities_1 = require("../../../utilities/event.utilities"); const helpers_1 = require("../../../utilities/helpers"); const data_moving_time_1 = require("../../../../data/data.moving-time"); const data_timer_time_1 = require("../../../../data/data.timer-time"); const utils_tcx_1 = require("./utils.tcx"); const data_total_cycles_1 = require("../../../../data/data-total-cycles"); const data_pace_avg_1 = require("../../../../data/data.pace-avg"); const activity_utilities_1 = require("../../../utilities/activity.utilities"); const data_power_avg_1 = require("../../../../data/data.power-avg"); const data_power_max_1 = require("../../../../data/data.power-max"); const data_cadence_avg_1 = require("../../../../data/data.cadence-avg"); const data_active_lap_1 = require("../../../../data/data-active-lap"); const data_swolf_25m_1 = require("../../../../data/data.swolf-25m"); const data_swolf_50m_1 = require("../../../../data/data.swolf-50m"); const file_type_enum_1 = require("../../file-type.enum"); const data_cadence_1 = require("../../../../data/data.cadence"); const activity_parsing_options_1 = require("../../../../activities/activity-parsing-options"); const stream_selection_1 = require("../../../../streams/stream.selection"); class EventImporterTCX { /** * Returns active or rest state of a lap. This is pretty use-full on swim pool activities which are decomposed of many active or rest laps */ static isActiveLap(lapElement) { const lapHasDistance = lapElement.getElementsByTagName('DistanceMeters').length > 0; const lapHasMaxSpeed = lapElement.getElementsByTagName('MaximumSpeed').length > 0; let lapDistance = 0; let lapMaxSpeed = 0; if (lapHasDistance) { lapDistance = Number(lapElement.getElementsByTagName('DistanceMeters')[0].textContent); } if (lapHasMaxSpeed) { lapMaxSpeed = Number(lapElement.getElementsByTagName('MaximumSpeed')[0].textContent); } return lapDistance > 0 || lapMaxSpeed > 0; } static getFromXML(xml, options = activity_parsing_options_1.ActivityParsingOptions.DEFAULT, name = 'New Event') { return new Promise(resolve => { const streamSelection = (0, stream_selection_1.getStreamSelectionFromOptions)(options); // Activities const activities = Array.from(xml.getElementsByTagName('TrainingCenterDatabase')[0].getElementsByTagName('Activity')).map(activityElement => { var _a; // Getting activity type const activityType = activity_types_1.ActivityTypes[activityElement.getAttribute('Sport') || 'unknown']; // TCX begins with laps, get them const laps = this.getLaps(activityElement.getElementsByTagName('Lap'), activityType); // Create activity const startDate = laps[0].startDate; const endDate = laps[laps.length - 1].endDate; let activity = new activity_1.Activity(startDate, endDate, activityType, this.getCreator(activityElement.getElementsByTagName('Creator')[0]), options); // Extract activity stats from laps retrieved activity = this.extractAndAssignActivityStatsFromLaps(laps, activity); // Extract activity stats provided by the root tcx file activity = this.extractAndAssignActivityStatsFromTcxRootDef(activityElement, activity); // Creates a array of track points elements let hasGpsData = false; const trackPointElements = Array.from(activityElement.getElementsByTagName('Lap')).reduce((trackPointElementArray, lapElement) => { Array.from(lapElement.getElementsByTagName('Trackpoint')).forEach(trackPointElement => { trackPointElementArray.push(trackPointElement); if (!hasGpsData) { hasGpsData = !!trackPointElement.getElementsByTagName('Position')[0]; } }); return trackPointElementArray; }, []); // Update activity type to indoor when no GPS data detected activity = this.updateActivityTypeCaseIndoor(hasGpsData, activity); if (!((_a = activity.getDistance()) === null || _a === void 0 ? void 0 : _a.getValue()) && trackPointElements.length && trackPointElements[trackPointElements.length - 1].getElementsByTagName('DistanceMeters')[0]) { // If the distance from laps is 0 and there is a last track-point with distance use that activity.setDistance(new data_distance_1.DataDistance(Number(trackPointElements[trackPointElements.length - 1].getElementsByTagName('DistanceMeters')[0].textContent))); } // Setup sample info which could be use when getting sample values const hasPowerMeter = trackPointElements.findIndex(trackPointElement => Number.isFinite((0, utils_tcx_1.findTrackPointExtensionValue)(trackPointElement.childNodes, 'Watts'))) !== -1; const samplesInfo = { hasPowerMeter: hasPowerMeter }; importer_tcx_mapper_1.TCXSampleMapper .filter(sampleMapping => (0, stream_selection_1.isStreamTypeAllowedForImport)(sampleMapping.dataType, streamSelection)) .forEach(sampleMapping => { // Should check the children const subjectTrackPointElements = trackPointElements.filter((element) => { return (0, helpers_1.isNumber)(sampleMapping.getSampleValue(element, samplesInfo)); }); if (subjectTrackPointElements.length) { if (activity.hasStreamData(sampleMapping.dataType)) { return; } activity.addStream(activity.createStream(sampleMapping.dataType)); subjectTrackPointElements.forEach((subjectTrackPointElement) => { if (!subjectTrackPointElement.getElementsByTagName('Time')[0]) { return; } activity.addDataToStream(sampleMapping.dataType, new Date(subjectTrackPointElement.getElementsByTagName('Time')[0].textContent), sampleMapping.getSampleValue(subjectTrackPointElement, samplesInfo)); }); } }); return activity; }); // Init the event const event = new event_1.Event(name, activities[0].startDate, activities[activities.length - 1].endDate, file_type_enum_1.FileType.TCX); activities.forEach(activity => event.addActivity(activity)); event_utilities_1.EventUtilities.generateStatsForAll(event); event.getActivities().forEach(activity => { (0, stream_selection_1.pruneActivityStreamsBySelection)(activity, streamSelection); }); resolve(event); }); } static updateActivityTypeCaseIndoor(hasGpsData, activity) { if (!hasGpsData) { switch (activity.type) { case activity_types_1.ActivityTypes.Running: activity.type = activity_types_1.ActivityTypes.IndoorRunning; break; case activity_types_1.ActivityTypes.Cycling: activity.type = activity_types_1.ActivityTypes.IndoorCycling; break; case activity_types_1.ActivityTypes.Rowing: activity.type = activity_types_1.ActivityTypes.IndoorRowing; break; } } return activity; } /** * Extract activity stats from laps retrieved */ static extractAndAssignActivityStatsFromLaps(laps, activity) { // Go over the laps and start filling up the stats and creating the points laps.forEach((lap) => { var _a, _b, _c, _d, _e, _f; if (lap.getDuration().getValue() === 0) { return; } // Append duration to whole activity if (((_a = lap.getDuration()) === null || _a === void 0 ? void 0 : _a.getValue()) > 0) { if (!activity.getDuration()) { activity.setDuration(new data_duration_1.DataDuration(0)); } activity.getDuration().setValue(activity.getDuration().getValue() + lap.getDuration().getValue()); } // Append timer time to whole activity if (((_b = lap.getTimer()) === null || _b === void 0 ? void 0 : _b.getValue()) > 0) { if (!activity.getTimer()) { activity.setTimer(new data_timer_time_1.DataTimerTime(0)); } activity.getTimer().setValue(activity.getTimer().getValue() + lap.getTimer().getValue()); } // Append elapsed time to whole activity const lapElapsed = lap.getStat(data_elapsed_time_1.DataElapsedTime.type); if ((lapElapsed === null || lapElapsed === void 0 ? void 0 : lapElapsed.getValue()) > 0) { if (!activity.getStat(data_elapsed_time_1.DataElapsedTime.type)) { activity.addStat(new data_elapsed_time_1.DataElapsedTime(0)); } activity.getStat(data_elapsed_time_1.DataElapsedTime.type).setValue(activity.getStat(data_elapsed_time_1.DataElapsedTime.type).getValue() + lapElapsed.getValue()); } // Append moving time to whole activity if (((_c = lap.getMovingTime()) === null || _c === void 0 ? void 0 : _c.getValue()) > 0) { if (!activity.getMovingTime()) { activity.setMovingTime(new data_moving_time_1.DataMovingTime(0)); } activity.getMovingTime().setValue(activity.getMovingTime().getValue() + lap.getMovingTime().getValue()); } // Append pause time to whole activity if (((_d = lap.getPause()) === null || _d === void 0 ? void 0 : _d.getValue()) > 0) { if (!activity.getPause()) { activity.setPause(new data_pause_1.DataPause(0)); } activity.getPause().setValue(activity.getPause().getValue() + lap.getPause().getValue()); } // Append distance to whole activity if (((_e = lap.getDistance()) === null || _e === void 0 ? void 0 : _e.getValue()) > 0) { if (!activity.getDistance()) { activity.setDistance(new data_distance_1.DataDistance(0)); } activity.getDistance().setValue(activity.getDistance().getValue() + lap.getDistance().getValue()); } // Append energy to whole activity if (((_f = lap.getStat(data_energy_1.DataEnergy.type)) === null || _f === void 0 ? void 0 : _f.getValue()) > 0) { if (!activity.getStat(data_energy_1.DataEnergy.type)) { activity.addStat(new data_energy_1.DataEnergy(0)); } activity.addStat(new data_energy_1.DataEnergy(activity.getStat(data_energy_1.DataEnergy.type).getValue() + lap.getStat(data_energy_1.DataEnergy.type).getValue())); } activity.addLap(lap); }); // Looping on laps to assign stats to activity if (laps === null || laps === void 0 ? void 0 : laps.length) { // Getting avg speed/pace from laps: const lapAvgSpeeds = laps .filter(lap => { var _a; return ((_a = lap.getStat(data_speed_avg_1.DataSpeedAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue()) >= 0; }) .map(lap => { var _a; return (_a = lap.getStat(data_speed_avg_1.DataSpeedAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue(); }); if (lapAvgSpeeds.length) { const avgSpeed = activity_utilities_1.ActivityUtilities.getAverage(lapAvgSpeeds); if (avgSpeed > 0) { activity.addStat(new data_speed_avg_1.DataSpeedAvg(avgSpeed)); activity.addStat(new data_pace_avg_1.DataPaceAvg((0, helpers_1.convertSpeedToPace)(avgSpeed))); } } // Cycles const lapTotalsCycles = laps .map(lap => { var _a; return ((_a = lap.getStat(data_total_cycles_1.DataTotalCycles.type)) === null || _a === void 0 ? void 0 : _a.getValue()) || 0; }) .filter(count => count > 0); if (lapTotalsCycles.length) { const lapTotalCycles = activity_utilities_1.ActivityUtilities.getSum(lapTotalsCycles); if (lapTotalCycles > 0) { activity.addStat(new data_total_cycles_1.DataTotalCycles(lapTotalCycles)); } } // Avg cadence const lapDataCadenceAverages = laps .map(lap => { var _a; return ((_a = lap.getStat(data_cadence_avg_1.DataCadenceAvg.type)) === null || _a === void 0 ? void 0 : _a.getValue()) || 0; }) .filter(cad => cad > 0); if (lapDataCadenceAverages.length) { const dataCadenceAvg = activity_utilities_1.ActivityUtilities.getAverage(lapDataCadenceAverages); if (dataCadenceAvg > 0) { activity.addStat(new data_cadence_avg_1.DataCadenceAvg(Math.round(dataCadenceAvg))); } } } return activity; } /** * Extract activity stats provided by the root tcx file */ static extractAndAssignActivityStatsFromTcxRootDef(activityElement, activity) { var _a, _b; if (!(((_a = activity.getStat(data_energy_1.DataEnergy.type)) === null || _a === void 0 ? void 0 : _a.getValue()) > 0) && activityElement.getElementsByTagName('Calories')[0]) { const calories = Number(activityElement.getElementsByTagName('Calories')[0].textContent); if (calories > 0) { activity.addStat(new data_energy_1.DataEnergy(calories)); } } if (!(((_b = activity.getStat(data_distance_1.DataDistance.type)) === null || _b === void 0 ? void 0 : _b.getValue()) > 0) && activityElement.getElementsByTagName('DistanceMeters')[0]) { activity.addStat(new data_distance_1.DataDistance(Number(activityElement.getElementsByTagName('DistanceMeters')[0].textContent))); } if (activityElement.getElementsByTagName('MaximumSpeed')[0]) { activity.addStat(new data_speed_max_1.DataSpeedMax(Number(activityElement.getElementsByTagName('MaximumSpeed')[0].textContent))); } return activity; } static getCreator(creatorElement) { const creator = new creator_1.Creator('Unknown Device'); if (!creatorElement) { return creator; } // Try to see if its a listed Suunto Device name if (creatorElement.getElementsByTagName('Name')[0]) { creator.name = importer_suunto_device_names_1.ImporterSuuntoDeviceNames[creatorElement.getElementsByTagName('Name')[0].textContent] || creatorElement.getElementsByTagName('Name')[0].textContent || creator.name; } if (creatorElement.getElementsByTagName('Version')[0]) { creator.swInfo = creatorElement.getElementsByTagName('Version')[0].textContent; } return creator; } static getLaps(lapElements, activityType) { return Array.from(lapElements).reduce((lapArray, lapElement, lapIndex) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; // Calculating lap time data (moving time, timer time, elapsed time...) const speedThreshold = activity_types_1.ActivityTypesMoving.getSpeedThreshold(activityType); let movingTime = 0; let elapsedTime = 0; let timerTime = lapElement.getElementsByTagName('TotalTimeSeconds').length ? Number(lapElement.getElementsByTagName('TotalTimeSeconds')[0].textContent) : 0; // Loop on track-points to detect moving speed const trackSpeeds = []; const trackElements = Array.from(lapElement.getElementsByTagName('Track')); trackElements.forEach(trackElement => { var _a; const trackPointsElements = Array.from(trackElement.getElementsByTagName('Trackpoint')); if (!(trackPointsElements === null || trackPointsElements === void 0 ? void 0 : trackPointsElements.length)) { return; } // Setting lap elapsed time from first and last track point const firstTrackPoint = trackPointsElements[0]; const lastTrackPoint = trackPointsElements[trackPointsElements.length - 1]; // Assign elapsed time if time available on first and last point if ((_a = lastTrackPoint === null || lastTrackPoint === void 0 ? void 0 : lastTrackPoint.getElementsByTagName('Time')) === null || _a === void 0 ? void 0 : _a.length) { elapsedTime = (new Date(lastTrackPoint.getElementsByTagName('Time')[0].textContent).getTime() - new Date(firstTrackPoint.getElementsByTagName('Time')[0].textContent).getTime()) / 1000; } // Parsing each track points to determine moving speed trackPointsElements.forEach((trackPointElement, index) => { // Skipping first record to be able to get delta with previous one if (index === 0) { return; } // Getting current time of track point const currentTime = new Date(trackPointElement.getElementsByTagName('Time')[0].textContent).getTime(); const previousTime = new Date(trackPointsElements[index - 1].getElementsByTagName('Time')[0].textContent).getTime(); const seconds = (currentTime - previousTime) / 1000; let speed = (0, utils_tcx_1.findTrackPointExtensionValue)(trackPointElement.childNodes, 'Speed'); // Try to get m/s using delta distance if speed extension is missing if (speed === null) { // If distance available on track point, then compute speed with it if (trackPointElement.getElementsByTagName('DistanceMeters').length && trackPointsElements[index - 1].getElementsByTagName('DistanceMeters').length) { const currentDistance = Number(trackPointElement.getElementsByTagName('DistanceMeters')[0].textContent); const previousDistance = Number(trackPointsElements[index - 1].getElementsByTagName('DistanceMeters')[0].textContent); const meters = currentDistance - previousDistance; speed = meters / seconds; trackSpeeds.push(speed); } } else { trackSpeeds.push(speed); } // We track moving time only if speed available on track points and upper than threshold if (speed !== null && speed > speedThreshold) { movingTime += seconds; } }); }); // Active or rest lap? const isActiveLap = this.isActiveLap(lapElement); // If elapsed time not defined or lower than timer time then use timer time as elapsed time if (!elapsedTime || timerTime > elapsedTime) { elapsedTime = timerTime; } // If timer time is missing, use elapsed time fallback for active duration. if (!timerTime && elapsedTime > 0) { timerTime = elapsedTime; } // If no moving time detected, try to detect from active laps if (movingTime === 0) { // Lap is considered as active. Track moving time.. if (isActiveLap) { movingTime = timerTime; } } // Now creating the lap let startDateStr = lapElement.getAttribute('StartTime'); // If no start time attribute found on lap, try to get it from first track point if (!startDateStr && trackElements.length > 0) { const firstTrackPoints = trackElements[0].getElementsByTagName('Trackpoint'); if (firstTrackPoints.length > 0) { startDateStr = (_a = firstTrackPoints[0].getElementsByTagName('Time')[0]) === null || _a === void 0 ? void 0 : _a.textContent; } } const startDate = startDateStr ? new Date(startDateStr) : new Date(0); const endDate = new Date(startDate); endDate.setSeconds(endDate.getSeconds() + elapsedTime); const lap = new lap_1.Lap(startDate, endDate, lapIndex + 1, lap_types_1.LapTypes.AutoLap); // Add elapsed, active duration and timer stats to lap const roundedElapsedTime = Math.round(elapsedTime * 10) / 10; const roundedTimerTime = Math.round(timerTime * 10) / 10; lap.addStat(new data_elapsed_time_1.DataElapsedTime(roundedElapsedTime)); lap.addStat(new data_duration_1.DataDuration(roundedTimerTime)); lap.addStat(new data_timer_time_1.DataTimerTime(roundedTimerTime)); // Append moving stat only if moving time has been detected // We need that to compute total global moving time later if (movingTime > 0) { lap.addStat(new data_moving_time_1.DataMovingTime(Math.round(movingTime * 10) / 10)); } // Pause TIME on Object (activity, lap...) const pause = elapsedTime > timerTime ? Math.round((elapsedTime - timerTime) * 100) / 100 : 0; lap.setPause(new data_pause_1.DataPause(pause)); // Assign is active lap status lap.addStat(new data_active_lap_1.DataActiveLap(isActiveLap)); if (lapElement.getElementsByTagName('TriggerMethod')[0]) { lap.type = lap_types_1.LapTypes[lapElement.getElementsByTagName('TriggerMethod')[0].textContent]; } if (lapElement.getElementsByTagName('Calories')[0]) { lap.addStat(new data_energy_1.DataEnergy(Number(lapElement.getElementsByTagName('Calories')[0].textContent))); } // Create a stats (required TCX fields) lap.addStat(new data_distance_1.DataDistance(0)); if (lapElement.getElementsByTagName('DistanceMeters')[0]) { lap.addStat(new data_distance_1.DataDistance(Number(lapElement.getElementsByTagName('DistanceMeters')[0].textContent))); } // Optionals if (trackSpeeds.length) { const maxSpeed = activity_utilities_1.ActivityUtilities.getMax(trackSpeeds); lap.addStat(new data_speed_max_1.DataSpeedMax(maxSpeed)); } else if (lapElement.getElementsByTagName('MaximumSpeed')[0]) { const maxSpeed = Number(lapElement.getElementsByTagName('MaximumSpeed')[0].textContent); lap.addStat(new data_speed_max_1.DataSpeedMax(maxSpeed)); } if (lapElement.getElementsByTagName('AverageHeartRateBpm')[0]) { const value = ((_c = (_b = lapElement.getElementsByTagName('AverageHeartRateBpm')[0]) === null || _b === void 0 ? void 0 : _b.getElementsByTagName('Value')[0]) === null || _c === void 0 ? void 0 : _c.textContent) || ((_d = lapElement.getElementsByTagName('AverageHeartRateBpm')[0]) === null || _d === void 0 ? void 0 : _d.textContent); if (value) { lap.addStat(new data_heart_rate_avg_1.DataHeartRateAvg(Number(value))); } } if (lapElement.getElementsByTagName('MaximumHeartRateBpm')[0]) { const value = ((_f = (_e = lapElement.getElementsByTagName('MaximumHeartRateBpm')[0]) === null || _e === void 0 ? void 0 : _e.getElementsByTagName('Value')[0]) === null || _f === void 0 ? void 0 : _f.textContent) || ((_g = lapElement.getElementsByTagName('MaximumHeartRateBpm')[0]) === null || _g === void 0 ? void 0 : _g.textContent); if (value) { lap.addStat(new data_heart_rate_max_1.DataHeartRateMax(Number(value))); } } if (lapElement.getElementsByTagName('Cadence')[0]) { lap.addStat(new data_cadence_1.DataCadence(Number(lapElement.getElementsByTagName('Cadence')[0].textContent))); } // Fetching activity lap speed from records or from extensions if exists according https://www8.garmin.com/xmlschemas/ActivityExtensionv2.xsd schema const lapAvgSpeed = trackSpeeds.length ? activity_utilities_1.ActivityUtilities.getAverage(trackSpeeds) : (0, utils_tcx_1.findLapExtensionValue)(lapElement.childNodes, 'AvgSpeed'); if (lapAvgSpeed !== null) { lap.addStat(new data_speed_avg_1.DataSpeedAvg(lapAvgSpeed)); lap.addStat(new data_pace_avg_1.DataPaceAvg((0, helpers_1.convertSpeedToPace)(lapAvgSpeed))); } // Cycles const lapTotalCycle = (0, utils_tcx_1.findLapExtensionValue)(lapElement.childNodes, 'Steps'); if (lapTotalCycle !== null) { lap.addStat(new data_total_cycles_1.DataTotalCycles(lapTotalCycle)); } // Avg Watts const lapAvgWatts = (0, utils_tcx_1.findLapExtensionValue)(lapElement.childNodes, 'AvgWatts'); if (lapAvgWatts !== null) { lap.addStat(new data_power_avg_1.DataPowerAvg(lapAvgWatts)); } // Max Watts const lapMaxWatts = (0, utils_tcx_1.findLapExtensionValue)(lapElement.childNodes, 'MaxWatts'); if (lapMaxWatts !== null) { lap.addStat(new data_power_max_1.DataPowerMax(lapMaxWatts)); } // AvgRunCadence const lapAvgRunCadence = (0, utils_tcx_1.findLapExtensionValue)(lapElement.childNodes, 'AvgRunCadence'); if (lapAvgRunCadence !== null) { lap.addStat(new data_cadence_avg_1.DataCadenceAvg(lapAvgRunCadence)); } // Try to set avg cadence from total cycle if not set on swimming activities only if (isActiveLap && (activityType === activity_types_1.ActivityTypes.Swimming || activityType === activity_types_1.ActivityTypes.OpenWaterSwimming) && !((_h = lap.getStat(data_cadence_avg_1.DataCadenceAvg.type)) === null || _h === void 0 ? void 0 : _h.getValue()) && timerTime && lapTotalCycle) { const lapAvgCadence = Math.round((lapTotalCycle / timerTime) * 60); lap.addStat(new data_cadence_avg_1.DataCadenceAvg(lapAvgCadence)); } // Average SWOLF in 25m and 50m pool if (isActiveLap && (activityType === activity_types_1.ActivityTypes.Swimming || activityType === activity_types_1.ActivityTypes.OpenWaterSwimming) && ((_j = lap.getStat(data_cadence_avg_1.DataCadenceAvg.type)) === null || _j === void 0 ? void 0 : _j.getValue()) > 0 && ((_k = lap.getStat(data_speed_avg_1.DataSpeedAvg.type)) === null || _k === void 0 ? void 0 : _k.getValue()) > 0) { const avgCadence = lap.getStat(data_cadence_avg_1.DataCadenceAvg.type).getValue(); const avgSpeed = lap.getStat(data_speed_avg_1.DataSpeedAvg.type).getValue(); const avgPace100m = (0, helpers_1.convertSpeedToSwimPace)(avgSpeed); const swolf25m = activity_utilities_1.ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 25); lap.addStat(new data_swolf_25m_1.DataSWOLF25m(swolf25m)); const swolf50m = activity_utilities_1.ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 50); lap.addStat(new data_swolf_50m_1.DataSWOLF50m(swolf50m)); } lapArray.push(lap); return lapArray; }, []); } } exports.EventImporterTCX = EventImporterTCX;