@sports-alliance/sports-lib 7.0.8 → 7.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/lib/cjs/data/data.array.d.ts +2 -3
  2. package/lib/cjs/data/data.array.js +1 -1
  3. package/lib/cjs/data/data.bare.d.ts +2 -1
  4. package/lib/cjs/data/data.d.ts +5 -5
  5. package/lib/cjs/data/data.number.d.ts +1 -2
  6. package/lib/cjs/data/data.position.d.ts +2 -3
  7. package/lib/cjs/data/data.position.js +1 -1
  8. package/lib/cjs/data/data.string.d.ts +2 -3
  9. package/lib/cjs/data/data.string.js +1 -1
  10. package/lib/esm/data/data.array.d.ts +2 -3
  11. package/lib/esm/data/data.bare.d.ts +2 -1
  12. package/lib/esm/data/data.d.ts +5 -5
  13. package/lib/esm/data/data.number.d.ts +1 -2
  14. package/lib/esm/data/data.position.d.ts +2 -3
  15. package/lib/esm/data/data.string.d.ts +2 -3
  16. package/lib/esm/index.js +12034 -152
  17. package/package.json +2 -2
  18. package/.editorconfig +0 -14
  19. package/.eslintignore +0 -4
  20. package/.eslintrc.js +0 -9
  21. package/.prettierignore +0 -25
  22. package/.prettierrc.json +0 -12
  23. package/CODE_OF_CONDUCT.md +0 -76
  24. package/jest.config.js +0 -23
  25. package/lib/esm/activities/activity-parsing-options.js +0 -19
  26. package/lib/esm/activities/activity.interface.js +0 -1
  27. package/lib/esm/activities/activity.js +0 -281
  28. package/lib/esm/activities/activity.json.interface.js +0 -1
  29. package/lib/esm/activities/activity.spec.js +0 -348
  30. package/lib/esm/activities/activity.types.js +0 -1046
  31. package/lib/esm/activities/activityt-types.spec.js +0 -16
  32. package/lib/esm/activities/devices/device.interface.js +0 -1
  33. package/lib/esm/activities/devices/device.js +0 -26
  34. package/lib/esm/activities/devices/device.json.interface.js +0 -1
  35. package/lib/esm/constants/constants.js +0 -8
  36. package/lib/esm/creators/creator.interface.js +0 -1
  37. package/lib/esm/creators/creator.js +0 -37
  38. package/lib/esm/creators/creator.json.interface.js +0 -1
  39. package/lib/esm/creators/creator.spec.js +0 -25
  40. package/lib/esm/data/data-active-lap.js +0 -4
  41. package/lib/esm/data/data-active-lengths.js +0 -4
  42. package/lib/esm/data/data-aerobic-training-effect.js +0 -8
  43. package/lib/esm/data/data-anaerobic-training-effect.js +0 -8
  44. package/lib/esm/data/data-stance-time-balance-left.js +0 -4
  45. package/lib/esm/data/data-stance-time-balance-right.js +0 -4
  46. package/lib/esm/data/data-stance-time-balance.js +0 -3
  47. package/lib/esm/data/data-store.spec.js +0 -78
  48. package/lib/esm/data/data-total-cycles.js +0 -4
  49. package/lib/esm/data/data.absolute-pressure.js +0 -5
  50. package/lib/esm/data/data.accumulated-power.js +0 -8
  51. package/lib/esm/data/data.activity-types.js +0 -7
  52. package/lib/esm/data/data.air-power-avg.js +0 -4
  53. package/lib/esm/data/data.air-power-max.js +0 -4
  54. package/lib/esm/data/data.air-power-min.js +0 -4
  55. package/lib/esm/data/data.air-power.js +0 -8
  56. package/lib/esm/data/data.alti-baro-profile.js +0 -4
  57. package/lib/esm/data/data.altitude-avg.js +0 -4
  58. package/lib/esm/data/data.altitude-gps.js +0 -5
  59. package/lib/esm/data/data.altitude-max.js +0 -4
  60. package/lib/esm/data/data.altitude-min.js +0 -4
  61. package/lib/esm/data/data.altitude-smooth.js +0 -4
  62. package/lib/esm/data/data.altitude.js +0 -8
  63. package/lib/esm/data/data.array.js +0 -13
  64. package/lib/esm/data/data.ascent-time.js +0 -4
  65. package/lib/esm/data/data.ascent.js +0 -4
  66. package/lib/esm/data/data.auto-lap-distance.js +0 -5
  67. package/lib/esm/data/data.auto-lap-duration.js +0 -4
  68. package/lib/esm/data/data.auto-lap-used.js +0 -7
  69. package/lib/esm/data/data.auto-pause-used.js +0 -7
  70. package/lib/esm/data/data.avg-stride-length.js +0 -4
  71. package/lib/esm/data/data.balance.js +0 -6
  72. package/lib/esm/data/data.bare.js +0 -4
  73. package/lib/esm/data/data.battery-charge.js +0 -8
  74. package/lib/esm/data/data.battery-consumption.js +0 -8
  75. package/lib/esm/data/data.battery-current.js +0 -8
  76. package/lib/esm/data/data.battery-life-estimation.js +0 -4
  77. package/lib/esm/data/data.battery-voltage.js +0 -8
  78. package/lib/esm/data/data.bike-pod-used.js +0 -7
  79. package/lib/esm/data/data.boolean.js +0 -9
  80. package/lib/esm/data/data.cadence-avg.js +0 -4
  81. package/lib/esm/data/data.cadence-max.js +0 -4
  82. package/lib/esm/data/data.cadence-min.js +0 -4
  83. package/lib/esm/data/data.cadence.js +0 -8
  84. package/lib/esm/data/data.cycling-dynamics.js +0 -3
  85. package/lib/esm/data/data.cycling-position.js +0 -37
  86. package/lib/esm/data/data.cycling-seated-time.js +0 -5
  87. package/lib/esm/data/data.cycling-standing-time.js +0 -5
  88. package/lib/esm/data/data.descent-time.js +0 -4
  89. package/lib/esm/data/data.descent.js +0 -4
  90. package/lib/esm/data/data.description.js +0 -4
  91. package/lib/esm/data/data.device-location.js +0 -4
  92. package/lib/esm/data/data.device-names.js +0 -7
  93. package/lib/esm/data/data.distance.js +0 -15
  94. package/lib/esm/data/data.duration.js +0 -56
  95. package/lib/esm/data/data.ehpe.js +0 -5
  96. package/lib/esm/data/data.enabled-navigation-systems.js +0 -4
  97. package/lib/esm/data/data.end-altitude.js +0 -4
  98. package/lib/esm/data/data.end-position.js +0 -4
  99. package/lib/esm/data/data.energy.js +0 -8
  100. package/lib/esm/data/data.epoc.js +0 -5
  101. package/lib/esm/data/data.event.js +0 -3
  102. package/lib/esm/data/data.evpe.js +0 -4
  103. package/lib/esm/data/data.feeling.js +0 -15
  104. package/lib/esm/data/data.foot-pod-used.js +0 -7
  105. package/lib/esm/data/data.form-power.js +0 -4
  106. package/lib/esm/data/data.fused-altitude.js +0 -7
  107. package/lib/esm/data/data.fused-location.js +0 -7
  108. package/lib/esm/data/data.gnss-distance.js +0 -4
  109. package/lib/esm/data/data.grade-adjusted-pace-avg.js +0 -15
  110. package/lib/esm/data/data.grade-adjusted-pace-max.js +0 -15
  111. package/lib/esm/data/data.grade-adjusted-pace-min.js +0 -15
  112. package/lib/esm/data/data.grade-adjusted-pace.js +0 -25
  113. package/lib/esm/data/data.grade-adjusted-speed-avg.js +0 -46
  114. package/lib/esm/data/data.grade-adjusted-speed-max.js +0 -46
  115. package/lib/esm/data/data.grade-adjusted-speed-min.js +0 -46
  116. package/lib/esm/data/data.grade-adjusted-speed.js +0 -78
  117. package/lib/esm/data/data.grade-smooth.js +0 -7
  118. package/lib/esm/data/data.grade.js +0 -7
  119. package/lib/esm/data/data.ground-time.js +0 -8
  120. package/lib/esm/data/data.heart-rate-avg.js +0 -4
  121. package/lib/esm/data/data.heart-rate-max.js +0 -4
  122. package/lib/esm/data/data.heart-rate-min.js +0 -4
  123. package/lib/esm/data/data.heart-rate-used.js +0 -7
  124. package/lib/esm/data/data.heart-rate-zone-five-duration.js +0 -4
  125. package/lib/esm/data/data.heart-rate-zone-four-duration.js +0 -4
  126. package/lib/esm/data/data.heart-rate-zone-one-duration.js +0 -4
  127. package/lib/esm/data/data.heart-rate-zone-three-duration.js +0 -4
  128. package/lib/esm/data/data.heart-rate-zone-two-duration.js +0 -4
  129. package/lib/esm/data/data.heart-rate.js +0 -8
  130. package/lib/esm/data/data.ibi.js +0 -8
  131. package/lib/esm/data/data.interface.js +0 -5
  132. package/lib/esm/data/data.js +0 -62
  133. package/lib/esm/data/data.json.interface.js +0 -1
  134. package/lib/esm/data/data.latitude-degrees.js +0 -5
  135. package/lib/esm/data/data.left-balance.js +0 -4
  136. package/lib/esm/data/data.leg-stiffness.js +0 -16
  137. package/lib/esm/data/data.longitude-degrees.js +0 -5
  138. package/lib/esm/data/data.moving-time.js +0 -4
  139. package/lib/esm/data/data.number-of-satellites.js +0 -7
  140. package/lib/esm/data/data.number-of.samples.js +0 -4
  141. package/lib/esm/data/data.number.js +0 -13
  142. package/lib/esm/data/data.pace-avg.js +0 -8
  143. package/lib/esm/data/data.pace-max.js +0 -8
  144. package/lib/esm/data/data.pace-min.js +0 -8
  145. package/lib/esm/data/data.pace.js +0 -46
  146. package/lib/esm/data/data.pause.js +0 -4
  147. package/lib/esm/data/data.peak-epoc.js +0 -7
  148. package/lib/esm/data/data.peak-training-effect.js +0 -4
  149. package/lib/esm/data/data.percent.js +0 -4
  150. package/lib/esm/data/data.pool-length.js +0 -5
  151. package/lib/esm/data/data.position.interface.js +0 -1
  152. package/lib/esm/data/data.position.js +0 -18
  153. package/lib/esm/data/data.power-avg.js +0 -4
  154. package/lib/esm/data/data.power-down.js +0 -4
  155. package/lib/esm/data/data.power-intensity-factor.js +0 -5
  156. package/lib/esm/data/data.power-left.js +0 -4
  157. package/lib/esm/data/data.power-max.js +0 -4
  158. package/lib/esm/data/data.power-min.js +0 -4
  159. package/lib/esm/data/data.power-normalized.js +0 -4
  160. package/lib/esm/data/data.power-pedal-smoothness-left.js +0 -4
  161. package/lib/esm/data/data.power-pedal-smoothness-right.js +0 -4
  162. package/lib/esm/data/data.power-pod-used.js +0 -7
  163. package/lib/esm/data/data.power-right.js +0 -4
  164. package/lib/esm/data/data.power-torque-effectiveness-left.js +0 -4
  165. package/lib/esm/data/data.power-torque-effectiveness-right.js +0 -4
  166. package/lib/esm/data/data.power-training-stress-score.js +0 -5
  167. package/lib/esm/data/data.power-up.js +0 -4
  168. package/lib/esm/data/data.power-work.js +0 -5
  169. package/lib/esm/data/data.power-zone-five-duration.js +0 -4
  170. package/lib/esm/data/data.power-zone-four-duration.js +0 -4
  171. package/lib/esm/data/data.power-zone-one-duration.js +0 -4
  172. package/lib/esm/data/data.power-zone-three-duration.js +0 -4
  173. package/lib/esm/data/data.power-zone-two-duration.js +0 -4
  174. package/lib/esm/data/data.power.js +0 -8
  175. package/lib/esm/data/data.recovery-time.js +0 -7
  176. package/lib/esm/data/data.rider-position-change-event.js +0 -8
  177. package/lib/esm/data/data.right-balance.js +0 -4
  178. package/lib/esm/data/data.rpe.js +0 -23
  179. package/lib/esm/data/data.satellite-5-best-snr.js +0 -4
  180. package/lib/esm/data/data.sea-level-pressure.js +0 -5
  181. package/lib/esm/data/data.spec.js +0 -25
  182. package/lib/esm/data/data.speed-avg.js +0 -46
  183. package/lib/esm/data/data.speed-max.js +0 -46
  184. package/lib/esm/data/data.speed-min.js +0 -46
  185. package/lib/esm/data/data.speed-zone-five-duration.js +0 -4
  186. package/lib/esm/data/data.speed-zone-four-duration.js +0 -4
  187. package/lib/esm/data/data.speed-zone-one-duration.js +0 -4
  188. package/lib/esm/data/data.speed-zone-three-duration.js +0 -4
  189. package/lib/esm/data/data.speed-zone-two-duration.js +0 -4
  190. package/lib/esm/data/data.speed.js +0 -88
  191. package/lib/esm/data/data.sport-profile-name.js +0 -4
  192. package/lib/esm/data/data.stance-time.js +0 -5
  193. package/lib/esm/data/data.start-altitude.js +0 -4
  194. package/lib/esm/data/data.start-event.js +0 -4
  195. package/lib/esm/data/data.start-position.js +0 -4
  196. package/lib/esm/data/data.step-length.js +0 -4
  197. package/lib/esm/data/data.steps-old.js +0 -4
  198. package/lib/esm/data/data.steps.js +0 -4
  199. package/lib/esm/data/data.stop-all-event.js +0 -4
  200. package/lib/esm/data/data.stop-event.js +0 -4
  201. package/lib/esm/data/data.store.export.spec.js +0 -66
  202. package/lib/esm/data/data.store.js +0 -1213
  203. package/lib/esm/data/data.string.js +0 -13
  204. package/lib/esm/data/data.stryd-altitude.js +0 -4
  205. package/lib/esm/data/data.stryd-distance.js +0 -4
  206. package/lib/esm/data/data.stryd-speed.js +0 -4
  207. package/lib/esm/data/data.swim-pace-avg.js +0 -8
  208. package/lib/esm/data/data.swim-pace-max.js +0 -8
  209. package/lib/esm/data/data.swim-pace-min.js +0 -8
  210. package/lib/esm/data/data.swim-pace.js +0 -19
  211. package/lib/esm/data/data.swolf-25m.js +0 -4
  212. package/lib/esm/data/data.swolf-50m.js +0 -4
  213. package/lib/esm/data/data.target-distance.js +0 -4
  214. package/lib/esm/data/data.target-heart-rate-zone.js +0 -4
  215. package/lib/esm/data/data.target-power-zone.js +0 -4
  216. package/lib/esm/data/data.target-speed-zone.js +0 -4
  217. package/lib/esm/data/data.target-time.js +0 -4
  218. package/lib/esm/data/data.temperature-avg.js +0 -4
  219. package/lib/esm/data/data.temperature-max.js +0 -4
  220. package/lib/esm/data/data.temperature-min.js +0 -4
  221. package/lib/esm/data/data.temperature.js +0 -8
  222. package/lib/esm/data/data.time.js +0 -6
  223. package/lib/esm/data/data.timer-time.js +0 -4
  224. package/lib/esm/data/data.vertical-oscillation.js +0 -5
  225. package/lib/esm/data/data.vertical-ratio.js +0 -5
  226. package/lib/esm/data/data.vertical-speed-avg.js +0 -53
  227. package/lib/esm/data/data.vertical-speed-max.js +0 -53
  228. package/lib/esm/data/data.vertical-speed-min.js +0 -53
  229. package/lib/esm/data/data.vertical-speed.js +0 -103
  230. package/lib/esm/data/data.vo2-max.js +0 -7
  231. package/lib/esm/data/ibi/data.ibi.filters.js +0 -52
  232. package/lib/esm/data/ibi/data.ibi.js +0 -98
  233. package/lib/esm/data/ibi/data.ibi.spec.js +0 -66
  234. package/lib/esm/duration/duration.class.abstract.js +0 -36
  235. package/lib/esm/duration/duration.class.interface.js +0 -1
  236. package/lib/esm/errors/duration-exceeded-event-lib.error.js +0 -9
  237. package/lib/esm/errors/empty-event-sports-libs.error.js +0 -9
  238. package/lib/esm/errors/event-lib.error.js +0 -8
  239. package/lib/esm/errors/lib.error.js +0 -6
  240. package/lib/esm/errors/parsing-event-lib.error.js +0 -9
  241. package/lib/esm/events/adapters/exporters/exporter.gpx.js +0 -75
  242. package/lib/esm/events/adapters/exporters/exporter.interface.js +0 -1
  243. package/lib/esm/events/adapters/exporters/exporter.json.js +0 -20
  244. package/lib/esm/events/adapters/file-type.enum.js +0 -7
  245. package/lib/esm/events/adapters/importers/fit/importer.fit.ant-plus.device.names.js +0 -25
  246. package/lib/esm/events/adapters/importers/fit/importer.fit.coros.device.names.js +0 -5
  247. package/lib/esm/events/adapters/importers/fit/importer.fit.development.device.names.js +0 -4
  248. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.device.names.js +0 -462
  249. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.data.js +0 -877
  250. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.js +0 -106
  251. package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.spec.js +0 -32
  252. package/lib/esm/events/adapters/importers/fit/importer.fit.hammerhead.device.names.js +0 -4
  253. package/lib/esm/events/adapters/importers/fit/importer.fit.integration.spec.js +0 -44
  254. package/lib/esm/events/adapters/importers/fit/importer.fit.js +0 -978
  255. package/lib/esm/events/adapters/importers/fit/importer.fit.lezyne.device.names.js +0 -3
  256. package/lib/esm/events/adapters/importers/fit/importer.fit.magellan.device.names.js +0 -5
  257. package/lib/esm/events/adapters/importers/fit/importer.fit.mapper.js +0 -231
  258. package/lib/esm/events/adapters/importers/fit/importer.fit.saris.device.names.js +0 -3
  259. package/lib/esm/events/adapters/importers/fit/importer.fit.spec.js +0 -326
  260. package/lib/esm/events/adapters/importers/fit/importer.fit.srm.device.names.js +0 -7
  261. package/lib/esm/events/adapters/importers/fit/importer.fit.suunto.device.names.js +0 -16
  262. package/lib/esm/events/adapters/importers/fit/importer.fit.wahoo.device.names.js +0 -10
  263. package/lib/esm/events/adapters/importers/gpx/gx-parser.js +0 -36
  264. package/lib/esm/events/adapters/importers/gpx/importer.gpx.integration.spec.js +0 -44
  265. package/lib/esm/events/adapters/importers/gpx/importer.gpx.js +0 -102
  266. package/lib/esm/events/adapters/importers/gpx/importer.gpx.mapper.js +0 -142
  267. package/lib/esm/events/adapters/importers/gpx/importer.gpx.spec.js +0 -71
  268. package/lib/esm/events/adapters/importers/json/importer.json.js +0 -160
  269. package/lib/esm/events/adapters/importers/sample-info.interface.js +0 -1
  270. package/lib/esm/events/adapters/importers/suunto/importer.suunto.activity.ids.js +0 -85
  271. package/lib/esm/events/adapters/importers/suunto/importer.suunto.device.names.js +0 -26
  272. package/lib/esm/events/adapters/importers/suunto/importer.suunto.integration.spec.js +0 -44
  273. package/lib/esm/events/adapters/importers/suunto/importer.suunto.json.js +0 -717
  274. package/lib/esm/events/adapters/importers/suunto/importer.suunto.sml.js +0 -125
  275. package/lib/esm/events/adapters/importers/tcx/importer.tcx.integration.spec.js +0 -46
  276. package/lib/esm/events/adapters/importers/tcx/importer.tcx.js +0 -442
  277. package/lib/esm/events/adapters/importers/tcx/importer.tcx.mapper.js +0 -91
  278. package/lib/esm/events/adapters/importers/tcx/utils.tcx.js +0 -36
  279. package/lib/esm/events/event.interface.js +0 -1
  280. package/lib/esm/events/event.js +0 -123
  281. package/lib/esm/events/event.json.interface.js +0 -1
  282. package/lib/esm/events/event.spec.js +0 -51
  283. package/lib/esm/events/utilities/activity.utilities.js +0 -1841
  284. package/lib/esm/events/utilities/activity.utilities.spec.js +0 -373
  285. package/lib/esm/events/utilities/event.utilities.js +0 -57
  286. package/lib/esm/events/utilities/grade-calculator/grade-calculator.js +0 -121
  287. package/lib/esm/events/utilities/grade-calculator/grade-calculator.spec.js +0 -93
  288. package/lib/esm/events/utilities/grade-calculator/low-pass-filter.js +0 -86
  289. package/lib/esm/events/utilities/helpers.js +0 -162
  290. package/lib/esm/geodesy/adapters/adapter.interface.js +0 -1
  291. package/lib/esm/geodesy/adapters/geolib.adapter.js +0 -28
  292. package/lib/esm/id/id.abstract.class.js +0 -9
  293. package/lib/esm/id/id.class.interface.js +0 -1
  294. package/lib/esm/id/id.class.spec.js +0 -13
  295. package/lib/esm/intensity-zones/intensity-zones.interface.js +0 -1
  296. package/lib/esm/intensity-zones/intensity-zones.js +0 -29
  297. package/lib/esm/intensity-zones/intensity-zones.json.interface.js +0 -1
  298. package/lib/esm/intensity-zones/intensity-zones.spec.js +0 -30
  299. package/lib/esm/laps/lap.interface.js +0 -1
  300. package/lib/esm/laps/lap.js +0 -29
  301. package/lib/esm/laps/lap.json.interface.js +0 -1
  302. package/lib/esm/laps/lap.types.js +0 -52
  303. package/lib/esm/meta-data/event-meta-data.interface.js +0 -6
  304. package/lib/esm/meta-data/meta-data.js +0 -57
  305. package/lib/esm/meta-data/meta-data.json.interface.js +0 -1
  306. package/lib/esm/privacy/privacy.class.interface.js +0 -5
  307. package/lib/esm/serializable/serializable.class.interface.js +0 -1
  308. package/lib/esm/service-tokens/oauth1-service-token.interface.js +0 -1
  309. package/lib/esm/service-tokens/oauth2-service-token.interface.js +0 -1
  310. package/lib/esm/specs/activities-parsing.integration.spec.js +0 -1847
  311. package/lib/esm/specs/activity-duration-stream.integration.spec.js +0 -57
  312. package/lib/esm/specs/fixtures/streams/strava/rides/3171472783.json +0 -52534
  313. package/lib/esm/specs/fixtures/streams/strava/rides/3171487458.json +0 -78818
  314. package/lib/esm/specs/fixtures/streams/strava/rides/343080886.json +0 -105090
  315. package/lib/esm/specs/fixtures/streams/strava/rides/5910143591.json +0 -110711
  316. package/lib/esm/specs/fixtures/streams/strava/runs/2451375851.json +0 -74846
  317. package/lib/esm/specs/fixtures/streams/strava/runs/2709634581.json +0 -66817
  318. package/lib/esm/specs/fixtures/streams/strava/runs/3156040843.json +0 -17594
  319. package/lib/esm/specs/fixtures/streams/strava/runs/3182900697.json +0 -17322
  320. package/lib/esm/specs/fixtures/streams/strava/runs/3183465494.json +0 -20463
  321. package/lib/esm/specs/fixtures/streams/strava/runs/3183490558.json +0 -58202
  322. package/lib/esm/specs/spec-utils.js +0 -159
  323. package/lib/esm/specs/strava-streams-compliance.spec.js +0 -951
  324. package/lib/esm/stats/stats.class.abstract.js +0 -32
  325. package/lib/esm/stats/stats.class.interface.js +0 -1
  326. package/lib/esm/stats/stats.json.interface.js +0 -1
  327. package/lib/esm/streams/compressed.stream.interface.js +0 -12
  328. package/lib/esm/streams/ibi-stream.js +0 -43
  329. package/lib/esm/streams/low-pass.stream.filter.js +0 -9
  330. package/lib/esm/streams/stream.filter.interface.js +0 -1
  331. package/lib/esm/streams/stream.interface.js +0 -1
  332. package/lib/esm/streams/stream.js +0 -72
  333. package/lib/esm/streams/stream.spec.js +0 -168
  334. package/lib/esm/tiles/tile.settings.interface.js +0 -41
  335. package/lib/esm/users/settings/dashboard/user.dashboard.settings.interface.js +0 -13
  336. package/lib/esm/users/settings/user.app.settings.interface.js +0 -5
  337. package/lib/esm/users/settings/user.chart.settings.interface.js +0 -23
  338. package/lib/esm/users/settings/user.map.settings.interface.js +0 -22
  339. package/lib/esm/users/settings/user.my-tracks.settings.interface.js +0 -1
  340. package/lib/esm/users/settings/user.settings.interface.js +0 -1
  341. package/lib/esm/users/settings/user.stats-settings.interface.js +0 -1
  342. package/lib/esm/users/settings/user.summaries.settings.interface.js +0 -1
  343. package/lib/esm/users/settings/user.unit.settings.interface.js +0 -73
  344. package/lib/esm/users/user.account.privileges.interface.js +0 -1
  345. package/lib/esm/users/user.export-to-csv.settings.interface.js +0 -1
  346. package/lib/esm/users/user.interface.js +0 -1
  347. package/lib/esm/users/user.js +0 -38
  348. package/lib/esm/users/user.service.meta.interface.js +0 -1
  349. package/tsconfig.cjs.json +0 -7
  350. package/tsconfig.esm.json +0 -8
  351. package/tsconfig.lib.json +0 -8
@@ -1,978 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { Event } from '../../../event';
11
- import { Activity } from '../../../../activities/activity';
12
- import { Lap } from '../../../../laps/lap';
13
- import { Creator } from '../../../../creators/creator';
14
- import { ActivityTypes, ActivityTypesMoving } from '../../../../activities/activity.types';
15
- import { DataDuration } from '../../../../data/data.duration';
16
- import { DataEnergy } from '../../../../data/data.energy';
17
- import { DataDistance } from '../../../../data/data.distance';
18
- import { ImporterFitSuuntoDeviceNames } from './importer.fit.suunto.device.names';
19
- import { GarminProfileMapper } from './importer.fit.garmin.profile.mapper';
20
- import { DataPause } from '../../../../data/data.pause';
21
- import { DataCadenceAvg } from '../../../../data/data.cadence-avg';
22
- import { DataPowerAvg } from '../../../../data/data.power-avg';
23
- import { DataSpeedAvg } from '../../../../data/data.speed-avg';
24
- import { DataCadenceMax } from '../../../../data/data.cadence-max';
25
- import { DataPowerMax } from '../../../../data/data.power-max';
26
- import { DataAscent } from '../../../../data/data.ascent';
27
- import { DataDescent } from '../../../../data/data.descent';
28
- import { DataHeartRateAvg } from '../../../../data/data.heart-rate-avg';
29
- import { DataHeartRateMax } from '../../../../data/data.heart-rate-max';
30
- import { DataSpeedMax } from '../../../../data/data.speed-max';
31
- import { LapTypes } from '../../../../laps/lap.types';
32
- import { DataHeartRateMin } from '../../../../data/data.heart-rate-min';
33
- import { DataPowerMin } from '../../../../data/data.power-min';
34
- import { DataAerobicTrainingEffect } from '../../../../data/data-aerobic-training-effect';
35
- import { FITSampleMapper } from './importer.fit.mapper';
36
- import { isNumber, isNumberOrString } from '../../../utilities/helpers';
37
- import { EventUtilities } from '../../../utilities/event.utilities';
38
- import { IBIStream } from '../../../../streams/ibi-stream';
39
- import { Device } from '../../../../activities/devices/device';
40
- import { ImporterFitAntPlusDeviceNames } from './importer.fit.ant-plus.device.names';
41
- import { DataRecoveryTime } from '../../../../data/data.recovery-time';
42
- import { DataPeakEPOC } from '../../../../data/data.peak-epoc';
43
- import { DataFeeling } from '../../../../data/data.feeling';
44
- import { DataTemperatureMax } from '../../../../data/data.temperature-max';
45
- import { DataTemperatureMin } from '../../../../data/data.temperature-min';
46
- import { DataTemperatureAvg } from '../../../../data/data.temperature-avg';
47
- import { DataSpeedMin } from '../../../../data/data.speed-min';
48
- import { DataCadenceMin } from '../../../../data/data.cadence-min';
49
- import { DataSWOLF25m } from '../../../../data/data.swolf-25m';
50
- import { DataDescription } from '../../../../data/data.description';
51
- import { DataVO2Max } from '../../../../data/data.vo2-max';
52
- import { IntensityZones } from '../../../../intensity-zones/intensity-zones';
53
- import { DataHeartRate } from '../../../../data/data.heart-rate';
54
- import { DataPower } from '../../../../data/data.power';
55
- import { DataSpeed } from '../../../../data/data.speed';
56
- import { DataHeartRateZoneOneDuration } from '../../../../data/data.heart-rate-zone-one-duration';
57
- import { DataHeartRateZoneTwoDuration } from '../../../../data/data.heart-rate-zone-two-duration';
58
- import { DataHeartRateZoneThreeDuration } from '../../../../data/data.heart-rate-zone-three-duration';
59
- import { DataHeartRateZoneFourDuration } from '../../../../data/data.heart-rate-zone-four-duration';
60
- import { DataHeartRateZoneFiveDuration } from '../../../../data/data.heart-rate-zone-five-duration';
61
- import { DataPowerZoneOneDuration } from '../../../../data/data.power-zone-one-duration';
62
- import { DataPowerZoneTwoDuration } from '../../../../data/data.power-zone-two-duration';
63
- import { DataPowerZoneThreeDuration } from '../../../../data/data.power-zone-three-duration';
64
- import { DataPowerZoneFourDuration } from '../../../../data/data.power-zone-four-duration';
65
- import { DataPowerZoneFiveDuration } from '../../../../data/data.power-zone-five-duration';
66
- import { DataSpeedZoneOneDuration } from '../../../../data/data.speed-zone-one-duration';
67
- import { DataSpeedZoneTwoDuration } from '../../../../data/data.speed-zone-two-duration';
68
- import { DataSpeedZoneThreeDuration } from '../../../../data/data.speed-zone-three-duration';
69
- import { DataSpeedZoneFourDuration } from '../../../../data/data.speed-zone-four-duration';
70
- import { DataSpeedZoneFiveDuration } from '../../../../data/data.speed-zone-five-duration';
71
- import { EmptyEventLibError } from '../../../../errors/empty-event-sports-libs.error';
72
- import { DataStartEvent } from '../../../../data/data.start-event';
73
- import { DataStopEvent } from '../../../../data/data.stop-event';
74
- import { DataStopAllEvent } from '../../../../data/data.stop-all-event';
75
- import { DataMovingTime } from '../../../../data/data.moving-time';
76
- import { ActivityUtilities } from '../../../utilities/activity.utilities';
77
- import { DataTimerTime } from '../../../../data/data.timer-time';
78
- import { DataTotalCycles } from '../../../../data/data-total-cycles';
79
- import { DataPoolLength } from '../../../../data/data.pool-length';
80
- import { DataActiveLengths } from '../../../../data/data-active-lengths';
81
- import { DataActiveLap } from '../../../../data/data-active-lap';
82
- import { DataSWOLF50m } from '../../../../data/data.swolf-50m';
83
- import { FileType } from '../../file-type.enum';
84
- import { DataPowerTorqueEffectivenessLeft } from '../../../../data/data.power-torque-effectiveness-left';
85
- import { DataPowerTorqueEffectivenessRight } from '../../../../data/data.power-torque-effectiveness-right';
86
- import { DataPowerPedalSmoothnessLeft } from '../../../../data/data.power-pedal-smoothness-left';
87
- import { DataPowerPedalSmoothnessRight } from '../../../../data/data.power-pedal-smoothness-right';
88
- import { DataPowerNormalized } from '../../../../data/data.power-normalized';
89
- import { DataPowerIntensityFactor } from '../../../../data/data.power-intensity-factor';
90
- import { DataPowerTrainingStressScore } from '../../../../data/data.power-training-stress-score';
91
- import { DataPowerWork } from '../../../../data/data.power-work';
92
- import { DataCyclingStandingTime } from '../../../../data/data.cycling-standing-time';
93
- import { DataCyclingSeatedTime } from '../../../../data/data.cycling-seated-time';
94
- import { RiderPosition } from '../../../../data/data.cycling-position';
95
- import { DataRiderPositionChangeEvent } from '../../../../data/data.rider-position-change-event';
96
- import { DataStanceTime } from '../../../../data/data.stance-time';
97
- import { DataVerticalOscillation } from '../../../../data/data.vertical-oscillation';
98
- import { DataVerticalRatio } from '../../../../data/data.vertical-ratio';
99
- import { DataAvgStrideLength } from '../../../../data/data.avg-stride-length';
100
- import { DataAnaerobicTrainingEffect } from '../../../../data/data-anaerobic-training-effect';
101
- import { ImporterFitWahooDeviceNames } from './importer.fit.wahoo.device.names';
102
- import { ImporterFitCorosDeviceNames } from './importer.fit.coros.device.names';
103
- import { ImporterFitSrmDeviceNames } from './importer.fit.srm.device.names';
104
- import { ActivityParsingOptions } from '../../../../activities/activity-parsing-options';
105
- import { ImporterFitHammerheadDeviceNames } from './importer.fit.hammerhead.device.names';
106
- import { ImporterFitLezyneDeviceNames } from './importer.fit.lezyne.device.names';
107
- import { ImporterFitMagellanDeviceNames } from './importer.fit.magellan.device.names';
108
- import { ImporterFitSarisDeviceNames } from './importer.fit.saris.device.names';
109
- import { ParsingEventLibError } from '../../../../errors/parsing-event-lib.error';
110
- import { DataPowerDown } from '../../../../data/data.power-down';
111
- import { DataPowerUp } from '../../../../data/data.power-up';
112
- import { ImporterFitDevelopmentDeviceNames } from './importer.fit.development.device.names';
113
- // eslint-disable-next-line @typescript-eslint/no-var-requires
114
- // @ts-ignore
115
- import FitFileParser from 'fit-file-parser';
116
- // Threshold to detect that session.timestamp are not trustable (when exceeding 15% of session.total_elapsed_time)
117
- const INVALID_DATES_ELAPSED_TIME_RATIO_THRESHOLD = 1.15;
118
- export class EventImporterFIT {
119
- static getFromArrayBuffer(arrayBuffer_1) {
120
- return __awaiter(this, arguments, void 0, function* (arrayBuffer, options = ActivityParsingOptions.DEFAULT, name = 'New Event') {
121
- return new Promise((resolve, reject) => {
122
- const fitFileParser = new FitFileParser({
123
- force: true,
124
- speedUnit: 'm/s',
125
- lengthUnit: 'm',
126
- temperatureUnit: 'celsius',
127
- elapsedRecordField: false,
128
- mode: 'both'
129
- });
130
- fitFileParser.parse(arrayBuffer, (error, fitDataObject) => {
131
- var _a;
132
- if (error) {
133
- // For now, assume any error from parser on this file means it's broken/empty in a way we treat as EmptyEventLibError
134
- // to satisfy existing tests. Or ideally we wrap in a generic EventLibError.
135
- // But test expects EmptyEventLibError.
136
- reject(new EmptyEventLibError());
137
- return;
138
- }
139
- if (!fitDataObject || !fitDataObject.sessions) {
140
- reject(new EmptyEventLibError());
141
- return;
142
- }
143
- // Check if we have length data at the top level (new parser behavior or missing mapping)
144
- if (fitDataObject.lengths && fitDataObject.lengths.length > 0) {
145
- (_a = fitDataObject.sessions) === null || _a === void 0 ? void 0 : _a.forEach((session) => {
146
- var _a;
147
- const sessionStartTime = new Date(session.start_time).getTime();
148
- const sessionEndTime = sessionStartTime + (session.total_elapsed_time || 0) * 1000;
149
- session.lengths = fitDataObject.lengths.filter((length) => {
150
- const lengthTime = new Date(length.timestamp || length.start_time).getTime();
151
- return lengthTime >= sessionStartTime && lengthTime < sessionEndTime;
152
- });
153
- // Also distribute to laps
154
- (_a = session.laps) === null || _a === void 0 ? void 0 : _a.forEach((lap) => {
155
- const lapStartTime = new Date(lap.start_time).getTime();
156
- const lapEndTime = lapStartTime + (lap.total_elapsed_time || 0) * 1000;
157
- lap.lengths = fitDataObject.lengths.filter((length) => {
158
- const lengthTime = new Date(length.timestamp || length.start_time).getTime();
159
- return lengthTime >= lapStartTime && lengthTime < lapEndTime;
160
- });
161
- });
162
- });
163
- }
164
- // Iterate over the sessions and create their activities
165
- const activities = fitDataObject.sessions.map((sessionObject) => {
166
- // Get the activity from the sessionObject
167
- const activity = this.getActivityFromSessionObject(sessionObject, fitDataObject, options);
168
- // Go over the laps
169
- sessionObject.laps.forEach((sessionLapObject, index) => {
170
- activity.addLap(this.getLapFromSessionLapObject(sessionLapObject, activity, index));
171
- });
172
- // Go over the hr zone info
173
- if (sessionObject.time_in_hr_zone && sessionObject.time_in_hr_zone.length) {
174
- // Add the stats
175
- if (isNumber(sessionObject.time_in_hr_zone[0])) {
176
- activity.addStat(new DataHeartRateZoneOneDuration(sessionObject.time_in_hr_zone[0]));
177
- }
178
- if (isNumber(sessionObject.time_in_hr_zone[1])) {
179
- activity.addStat(new DataHeartRateZoneTwoDuration(sessionObject.time_in_hr_zone[1]));
180
- }
181
- if (isNumber(sessionObject.time_in_hr_zone[2])) {
182
- activity.addStat(new DataHeartRateZoneThreeDuration(sessionObject.time_in_hr_zone[2]));
183
- }
184
- if (isNumber(sessionObject.time_in_hr_zone[3])) {
185
- activity.addStat(new DataHeartRateZoneFourDuration(sessionObject.time_in_hr_zone[3]));
186
- }
187
- if (isNumber(sessionObject.time_in_hr_zone[4])) {
188
- activity.addStat(new DataHeartRateZoneFiveDuration(sessionObject.time_in_hr_zone[4]));
189
- }
190
- const hrIntensityZones = new IntensityZones(DataHeartRate.type);
191
- hrIntensityZones.zone1Duration = sessionObject.time_in_hr_zone[0] || 0;
192
- hrIntensityZones.zone2Duration = sessionObject.time_in_hr_zone[1] || 0;
193
- hrIntensityZones.zone3Duration = sessionObject.time_in_hr_zone[2] || 0;
194
- hrIntensityZones.zone4Duration = sessionObject.time_in_hr_zone[3] || 0;
195
- hrIntensityZones.zone5Duration = sessionObject.time_in_hr_zone[4] || 0;
196
- activity.intensityZones.push(hrIntensityZones);
197
- }
198
- // Go over the power zone info
199
- if (sessionObject.time_in_power_zone && sessionObject.time_in_power_zone.length) {
200
- if (isNumber(sessionObject.time_in_power_zone[0])) {
201
- activity.addStat(new DataPowerZoneOneDuration(sessionObject.time_in_power_zone[0]));
202
- }
203
- if (isNumber(sessionObject.time_in_power_zone[1])) {
204
- activity.addStat(new DataPowerZoneTwoDuration(sessionObject.time_in_power_zone[1]));
205
- }
206
- if (isNumber(sessionObject.time_in_power_zone[2])) {
207
- activity.addStat(new DataPowerZoneThreeDuration(sessionObject.time_in_power_zone[2]));
208
- }
209
- if (isNumber(sessionObject.time_in_power_zone[3])) {
210
- activity.addStat(new DataPowerZoneFourDuration(sessionObject.time_in_power_zone[3]));
211
- }
212
- if (isNumber(sessionObject.time_in_power_zone[4])) {
213
- activity.addStat(new DataPowerZoneFiveDuration(sessionObject.time_in_power_zone[4]));
214
- }
215
- const powerIntensityZones = new IntensityZones(DataPower.type);
216
- powerIntensityZones.zone1Duration = sessionObject.time_in_power_zone[0] || 0;
217
- powerIntensityZones.zone2Duration = sessionObject.time_in_power_zone[1] || 0;
218
- powerIntensityZones.zone3Duration = sessionObject.time_in_power_zone[2] || 0;
219
- powerIntensityZones.zone4Duration = sessionObject.time_in_power_zone[3] || 0;
220
- powerIntensityZones.zone5Duration = sessionObject.time_in_power_zone[4] || 0;
221
- activity.intensityZones.push(powerIntensityZones);
222
- }
223
- // Go over the speed zone info
224
- if (sessionObject.time_in_speed_zone && sessionObject.time_in_speed_zone.length) {
225
- if (isNumber(sessionObject.time_in_speed_zone[0])) {
226
- activity.addStat(new DataSpeedZoneOneDuration(sessionObject.time_in_speed_zone[0]));
227
- }
228
- if (isNumber(sessionObject.time_in_speed_zone[1])) {
229
- activity.addStat(new DataSpeedZoneTwoDuration(sessionObject.time_in_speed_zone[1]));
230
- }
231
- if (isNumber(sessionObject.time_in_speed_zone[2])) {
232
- activity.addStat(new DataSpeedZoneThreeDuration(sessionObject.time_in_speed_zone[2]));
233
- }
234
- if (isNumber(sessionObject.time_in_speed_zone[3])) {
235
- activity.addStat(new DataSpeedZoneFourDuration(sessionObject.time_in_speed_zone[3]));
236
- }
237
- if (isNumber(sessionObject.time_in_speed_zone[4])) {
238
- activity.addStat(new DataSpeedZoneFiveDuration(sessionObject.time_in_speed_zone[4]));
239
- }
240
- const speedIntensityZones = new IntensityZones(DataSpeed.type);
241
- speedIntensityZones.zone1Duration = sessionObject.time_in_speed_zone[0] || 0;
242
- speedIntensityZones.zone2Duration = sessionObject.time_in_speed_zone[1] || 0;
243
- speedIntensityZones.zone3Duration = sessionObject.time_in_speed_zone[2] || 0;
244
- speedIntensityZones.zone4Duration = sessionObject.time_in_speed_zone[3] || 0;
245
- speedIntensityZones.zone5Duration = sessionObject.time_in_speed_zone[4] || 0;
246
- activity.intensityZones.push(speedIntensityZones);
247
- }
248
- // Add the events
249
- fitDataObject.events
250
- .filter((activityEvent) => {
251
- return activityEvent.timestamp >= activity.startDate && activityEvent.timestamp <= activity.endDate;
252
- })
253
- .forEach((activityEvent) => {
254
- if (activityEvent.event === 'timer') {
255
- switch (activityEvent.event_type) {
256
- case 'start':
257
- activity.addEvent(new DataStartEvent(activity.getDateIndex(activityEvent.timestamp)));
258
- break;
259
- case 'stop':
260
- activity.addEvent(new DataStopEvent(activity.getDateIndex(activityEvent.timestamp)));
261
- break;
262
- case 'stop_all':
263
- activity.addEvent(new DataStopAllEvent(activity.getDateIndex(activityEvent.timestamp)));
264
- break;
265
- default:
266
- break;
267
- }
268
- }
269
- else if (activityEvent.event === 'power_down') {
270
- activity.addEvent(new DataPowerDown(activity.getDateIndex(activityEvent.timestamp)));
271
- }
272
- else if (activityEvent.event === 'power_up') {
273
- activity.addEvent(new DataPowerUp(activity.getDateIndex(activityEvent.timestamp)));
274
- }
275
- else if (activityEvent.event === 'rider_position_change') {
276
- const positionChange = activityEvent.data;
277
- if (positionChange === RiderPosition.SEATED ||
278
- positionChange === RiderPosition.STANDING ||
279
- positionChange === RiderPosition.TRANSITION_TO_SEATED ||
280
- positionChange === RiderPosition.TRANSITION_TO_STANDING) {
281
- activity.addEvent(new DataRiderPositionChangeEvent(activity.getDateIndex(activityEvent.timestamp), positionChange));
282
- }
283
- }
284
- });
285
- // Get the samples..
286
- // Test if activity is lengths based
287
- // Indeed when based on lengths, an activity do not provides samples under records object (e.g. Pool swimming activities)
288
- // Note: this is how Strava generate streams for this kind of activities
289
- const isLengthsBased = this.isLengthsBased(sessionObject);
290
- const samples = isLengthsBased
291
- ? this.generateSamplesFromLengths(sessionObject, options)
292
- : fitDataObject.records.filter((record) => {
293
- return record.timestamp >= activity.startDate && record.timestamp <= activity.endDate;
294
- });
295
- // Setup sample info which could be use when getting sample values
296
- const hasPowerMeter = samples.findIndex((sample) => Number.isFinite(isNumber(sample.power) ? sample.power : isNumber(sample.Power) ? sample.Power : sample.RP_Power)) !== -1;
297
- const samplesInfo = { hasPowerMeter: hasPowerMeter };
298
- FITSampleMapper.forEach(sampleMapping => {
299
- // @todo not sure if we need to check for number only ...
300
- const subjectSamples = (samples.filter((sample) => isNumber(sampleMapping.getSampleValue(sample, samplesInfo))));
301
- if (subjectSamples.length) {
302
- // When we create a stream here it has the length of the activity elapsed time (end-start) filled with nulls.
303
- // We keep nulls in order to preserve the array length.
304
- activity.addStream(activity.createStream(sampleMapping.dataType));
305
- subjectSamples.forEach(subjectSample => {
306
- activity.addDataToStream(sampleMapping.dataType, new Date(subjectSample.timestamp), sampleMapping.getSampleValue(subjectSample, samplesInfo));
307
- });
308
- }
309
- });
310
- return activity;
311
- });
312
- // If there are no activities to parse ....
313
- if (!activities.length) {
314
- reject(new EmptyEventLibError());
315
- return;
316
- }
317
- // Get the HRV to IBI if exist
318
- if (fitDataObject.hrv && fitDataObject.hrv.length) {
319
- activities.forEach((activity) => {
320
- let timeSum = 0;
321
- const ibiData = fitDataObject.hrv
322
- .reduce((ibiArray, hrvRecord) => ibiArray.concat(hrvRecord.time), [])
323
- .map((ibi) => ibi * 1000)
324
- .filter((ibi) => {
325
- // debugger;
326
- // Some Garmin devices return a record of 65.535 (65535) for some reason so exlcude those
327
- if (ibi === 65535) {
328
- // timeSum += ibi;
329
- return false;
330
- }
331
- timeSum += ibi;
332
- const ibiDataDate = new Date(activities[0].startDate.getTime() + timeSum);
333
- return ibiDataDate >= activity.startDate && ibiDataDate <= activity.endDate;
334
- });
335
- // set the IBI
336
- activity.addStream(new IBIStream(ibiData));
337
- });
338
- }
339
- // Parse the device infos
340
- if (fitDataObject.device_infos && fitDataObject.device_infos.length) {
341
- activities.forEach(activity => {
342
- activity.creator.devices = this.getDeviceInfos(fitDataObject.device_infos);
343
- });
344
- }
345
- // Create an event
346
- // @todo check if the start and end date can derive from the file
347
- const event = new Event(name, activities[0].startDate, activities[activities.length - 1].endDate, FileType.FIT);
348
- activities.forEach(activity => event.addActivity(activity));
349
- // debugger;
350
- EventUtilities.generateStatsForAll(event);
351
- // debugger;
352
- resolve(event);
353
- });
354
- });
355
- });
356
- }
357
- /**
358
- * Tell if an activity is lengths based (e.g. Pool swimming activities)
359
- * @param sessionObject
360
- * @private
361
- */
362
- static isLengthsBased(sessionObject) {
363
- var _a;
364
- return ((_a = sessionObject.laps) === null || _a === void 0 ? void 0 : _a.filter((lap) => { var _a; return (_a = lap.lengths) === null || _a === void 0 ? void 0 : _a.length; }).length) > 1;
365
- }
366
- /**
367
- * Generate streams samples based on lengths on an activity
368
- * When based on lengths, an activity do not provides sample under records object
369
- * @param sessionObject
370
- * @param options
371
- * @private
372
- */
373
- static generateSamplesFromLengths(sessionObject, options) {
374
- if (!this.isLengthsBased(sessionObject)) {
375
- throw new ParsingEventLibError('Trying to get samples from activities lengths, but no lengths is available');
376
- }
377
- let samples = [];
378
- // Loop on every laps to catch every lengths where data is (speed, cadence, hr, ...)
379
- sessionObject.laps.forEach((lap) => {
380
- var _a;
381
- // Loop on every laps
382
- if ((_a = lap.lengths) === null || _a === void 0 ? void 0 : _a.length) {
383
- // Get length in meters from lap total distance and total number of lengths
384
- // We will use it to generate the distance stream below
385
- const lengthMeters = lap.total_distance / lap.lengths.length;
386
- // For each length of every laps build the streams data we will need for a later use
387
- lap.lengths.forEach((length) => {
388
- // Resolve start/end date of current length
389
- const lengthStartDate = length.start_time;
390
- const lengthDuration = (length.total_timer_time || length.total_elapsed_time || 0);
391
- const lengthEndDate = new Date(lengthStartDate.getTime() + lengthDuration * 1000);
392
- // We check if length is valid comparing to max activity duration
393
- if (lengthDuration > options.maxActivityDurationDays * 24 * 60 * 60) {
394
- return;
395
- }
396
- if (lengthEndDate.getTime() <= lengthStartDate.getTime()) {
397
- return;
398
- }
399
- // Generate a stream from length start date to end date filled by null values
400
- const streamLength = ActivityUtilities.getDataLength(lengthStartDate, lengthEndDate);
401
- let lengthStream = Array(streamLength).fill(null);
402
- // Define distance step to be used for distance stream
403
- const lengthStepSize = lengthMeters / (lengthStream.length - 1);
404
- // Generate the length stream based on data we have on current length
405
- lengthStream = lengthStream.map((value, index) => {
406
- var _a;
407
- return {
408
- timestamp: new Date(lengthStartDate.getTime() + index * 1000),
409
- distance: (((_a = samples[samples.length - 1]) === null || _a === void 0 ? void 0 : _a.distance) || 0) + lengthStepSize * index,
410
- speed: length.avg_speed || lap.avg_speed,
411
- cadence: length.avg_cadence || length.avg_swimming_cadence || lap.avg_cadence,
412
- heart_rate: length.avg_heart_rate || lap.avg_heart_rate
413
- };
414
- });
415
- // Append to existing samples
416
- samples = samples.concat(lengthStream);
417
- });
418
- }
419
- });
420
- return samples;
421
- }
422
- static getDeviceInfos(deviceInfos) {
423
- return deviceInfos.map((deviceInfo) => {
424
- const device = new Device(deviceInfo.device_type);
425
- device.index = deviceInfo.device_index;
426
- device.name = deviceInfo.product_name || ImporterFitAntPlusDeviceNames[deviceInfo.ant_device_number] || deviceInfo.ant_device_number;
427
- device.batteryStatus = deviceInfo.battery_status;
428
- device.batteryLevel = isNumber(deviceInfo.battery_level) ? deviceInfo.battery_level : deviceInfo.battery_soc;
429
- device.batteryVoltage = deviceInfo.battery_voltage;
430
- device.manufacturer = deviceInfo.manufacturer;
431
- device.serialNumber = deviceInfo.serial_number;
432
- device.product = deviceInfo.product;
433
- device.swInfo = deviceInfo.software_version;
434
- device.hwInfo = deviceInfo.hardware_version;
435
- device.antDeviceNumber = deviceInfo.ant_device_number;
436
- device.antTransmissionType = deviceInfo.ant_transmission_type;
437
- device.antNetwork = deviceInfo.ant_network;
438
- device.sourceType = deviceInfo.source_type;
439
- device.cumOperatingTime = deviceInfo.cum_operating_time;
440
- return device;
441
- });
442
- }
443
- static getLapFromSessionLapObject(sessionLapObject, activity, lapIndex) {
444
- var _a, _b, _c;
445
- const startDate = (sessionLapObject === null || sessionLapObject === void 0 ? void 0 : sessionLapObject.start_time) ||
446
- ((_a = sessionLapObject === null || sessionLapObject === void 0 ? void 0 : sessionLapObject.records[0]) === null || _a === void 0 ? void 0 : _a.timestamp) ||
447
- ((sessionLapObject === null || sessionLapObject === void 0 ? void 0 : sessionLapObject.total_elapsed_time) &&
448
- new Date(sessionLapObject.timestamp.getTime() - sessionLapObject.total_elapsed_time * 1000)) ||
449
- null;
450
- const endDate = (sessionLapObject === null || sessionLapObject === void 0 ? void 0 : sessionLapObject.timestamp) ||
451
- (((_b = sessionLapObject.records) === null || _b === void 0 ? void 0 : _b.length) > 0 &&
452
- ((_c = sessionLapObject.records[sessionLapObject.records.length - 1]) === null || _c === void 0 ? void 0 : _c.timestamp)) ||
453
- (sessionLapObject.start_time &&
454
- sessionLapObject.total_elapsed_time &&
455
- new Date(sessionLapObject.start_time.getTime() + sessionLapObject.total_elapsed_time * 1000)) ||
456
- null;
457
- const lap = new Lap(startDate, endDate, // Some dont have a timestamp
458
- lapIndex + 1, LapTypes[sessionLapObject.lap_trigger] || LapTypes.unknown);
459
- // Set the calories
460
- if (sessionLapObject.total_calories) {
461
- lap.addStat(new DataEnergy(sessionLapObject.total_calories));
462
- }
463
- // Add stats to the lap
464
- this.getStatsFromObject(sessionLapObject, activity, true).forEach(stat => lap.addStat(stat));
465
- return lap;
466
- }
467
- static getActivityFromSessionObject(sessionObject, fitDataObject, options) {
468
- /**
469
- * Provides start/end date based on records available in given session object first, then in parent fit object
470
- */
471
- const getStartEndDatesFromRecords = (sessionObject, fitDataObject) => {
472
- var _a, _b, _c, _d, _e, _f, _g, _h;
473
- let startDate = null;
474
- let endDate = null;
475
- // Try to get from session first
476
- if (((_a = sessionObject === null || sessionObject === void 0 ? void 0 : sessionObject.laps) === null || _a === void 0 ? void 0 : _a.length) > 0 && // Current session has laps
477
- ((_b = sessionObject.laps[0].records) === null || _b === void 0 ? void 0 : _b.length) > 0 && // Current session has records in first lap
478
- ((_c = sessionObject.laps[sessionObject.laps.length - 1].records) === null || _c === void 0 ? void 0 : _c.length) > 0 // Current session has records in last lap
479
- ) {
480
- const firstLapRecords = sessionObject.laps[0].records;
481
- const firstRecordTimeStamp = (_d = firstLapRecords[0]) === null || _d === void 0 ? void 0 : _d.timestamp;
482
- if (firstRecordTimeStamp) {
483
- startDate = firstRecordTimeStamp;
484
- }
485
- const lastLapRecords = sessionObject.laps[sessionObject.laps.length - 1].records;
486
- const lastRecordTimeStamp = (_e = lastLapRecords[lastLapRecords.length - 1]) === null || _e === void 0 ? void 0 : _e.timestamp;
487
- if (lastRecordTimeStamp) {
488
- endDate = lastRecordTimeStamp;
489
- }
490
- }
491
- // Then from parent fit object first
492
- if ((!startDate || !endDate) && ((_f = fitDataObject.records) === null || _f === void 0 ? void 0 : _f.length)) {
493
- startDate = ((_g = fitDataObject.records[0]) === null || _g === void 0 ? void 0 : _g.timestamp) || null;
494
- endDate = ((_h = fitDataObject.records[fitDataObject.records.length - 1]) === null || _h === void 0 ? void 0 : _h.timestamp) || null;
495
- }
496
- return [startDate, endDate];
497
- };
498
- // For some unknown reasons... the fit provided total_timer_time & total_elapsed_time could be inverted..
499
- // Just invert fields if that's the case
500
- this.swapTimesIfRequired(sessionObject);
501
- // Start finding out total elapsed time from fit dedicated fields
502
- const totalElapsedTime = sessionObject.total_elapsed_time || sessionObject.total_timer_time || 0;
503
- // Pick start/end date values
504
- let startDate = sessionObject.start_time || getStartEndDatesFromRecords(sessionObject, fitDataObject)[0] || null;
505
- let endDate = sessionObject.timestamp ||
506
- (startDate && totalElapsedTime && new Date(startDate.getTime() + totalElapsedTime * 1000)) ||
507
- getStartEndDatesFromRecords(sessionObject, fitDataObject)[1] ||
508
- null;
509
- // Some fit files have wrong dates for session.timestamp && session.start_time and those miss an elapsed time
510
- // Get dates from records in that case
511
- if (!totalElapsedTime // Elapsed time missing
512
- ) {
513
- const [startDateResult, endDateResult] = getStartEndDatesFromRecords(sessionObject, fitDataObject);
514
- if (startDateResult) {
515
- startDate = startDateResult;
516
- }
517
- if (endDateResult) {
518
- endDate = endDateResult;
519
- }
520
- }
521
- // Now verify the start/end date compliance,
522
- // If for some reason this happens, get from records too
523
- if (endDate <= startDate) {
524
- const [startDateResult, endDateResult] = getStartEndDatesFromRecords(sessionObject, fitDataObject);
525
- if (startDateResult) {
526
- startDate = startDateResult;
527
- }
528
- if (endDateResult) {
529
- endDate = endDateResult;
530
- }
531
- }
532
- const elapsedTimeFromDates = (+endDate - +startDate) / 1000; // Get elapsed calculated from dates
533
- // Test case where sometime elapsed time (calculated from dates) can be very high comparing to computed totalElapsedTime
534
- // If elapsed time (calculated from dates) is detected as "strange" then use elapsed time from fit fields instead
535
- // @see test case implying 'fixtures/rides/fit/5319808632.fit' fit file
536
- if (elapsedTimeFromDates / totalElapsedTime > INVALID_DATES_ELAPSED_TIME_RATIO_THRESHOLD) {
537
- if (totalElapsedTime) {
538
- endDate = new Date(sessionObject.start_time.getTime() + totalElapsedTime * 1000);
539
- }
540
- }
541
- // Re-test potential updated activity duration against max accepted duration
542
- if (+endDate - +startDate > options.maxActivityDurationDays * 24 * 60 * 60 * 1000) {
543
- endDate = new Date(sessionObject.start_time.getTime() + totalElapsedTime * 1000);
544
- }
545
- if (!startDate || !endDate) {
546
- throw new ParsingEventLibError('Cannot parse start and end dates');
547
- }
548
- else {
549
- // Create an activity
550
- const activity = new Activity(startDate, endDate, this.getActivityTypeFromSessionObject(sessionObject), this.getCreatorFromFitDataObject(fitDataObject), options);
551
- // Set the activity stats
552
- this.getStatsFromObject(sessionObject, activity, false).forEach(stat => activity.addStat(stat));
553
- return activity;
554
- }
555
- }
556
- /**
557
- * For some unknown reasons... the fit provided total_timer_time & total_elapsed_time could be inverted..
558
- * Just swap them if that's the case
559
- */
560
- static swapTimesIfRequired(object) {
561
- if (isNumber(object.total_timer_time) &&
562
- isNumber(object.total_elapsed_time) &&
563
- object.total_elapsed_time < object.total_timer_time) {
564
- const realTimerTime = object.total_elapsed_time;
565
- const realElapsedTime = object.total_timer_time;
566
- object.total_timer_time = realTimerTime;
567
- object.total_elapsed_time = realElapsedTime;
568
- }
569
- }
570
- static getActivityTypeFromSessionObject(session) {
571
- const activityTypeKey = session.sub_sport && session.sub_sport !== 'generic' ? `${session.sport}_${session.sub_sport}` : session.sport;
572
- let activityType = ActivityTypes[activityTypeKey];
573
- if (!activityType || activityType === ActivityTypes.unknown) {
574
- // Fallback to Garmin SDK mappings
575
- const sportName = GarminProfileMapper.getSportName(session.sport);
576
- const subSportName = session.sub_sport && session.sub_sport !== 'generic'
577
- ? GarminProfileMapper.getSubSportName(session.sub_sport)
578
- : null;
579
- if (sportName || subSportName) {
580
- // Try to find in ActivityTypes using the name from Garmin SDK
581
- const nameKey = subSportName ? `${sportName}_${subSportName}` : sportName;
582
- activityType =
583
- ActivityTypes[nameKey] ||
584
- ActivityTypes[sportName] ||
585
- nameKey;
586
- }
587
- }
588
- return activityType || session.sport || ActivityTypes.unknown;
589
- }
590
- // @todo move this to a mapper
591
- static getStatsFromObject(object, activity, isLap) {
592
- const stats = [];
593
- // For some unknown reasons... the fit provided total_timer_time & total_elapsed_time could be inverted..
594
- // Just invert fields if that's the case
595
- this.swapTimesIfRequired(object);
596
- // TOTAL ELAPSED TIME on Object (activity, lap...)
597
- let elapsedTime = 0;
598
- if (isNumber(object.total_elapsed_time)) {
599
- elapsedTime = object.total_elapsed_time;
600
- }
601
- else if ((object.timestamp - object.start_time) / 1000) {
602
- elapsedTime = (object.timestamp - object.start_time) / 1000;
603
- }
604
- // 0 should be not included aha it's not legit to have a 0 for total timer time
605
- // And that typically is a device error we should look at the samples
606
- // Since start and end date are inclusive for sample size eg at time [0] there can be a value
607
- if (!elapsedTime) {
608
- elapsedTime = ActivityUtilities.getDataLength(activity.startDate, activity.endDate) - 1;
609
- }
610
- stats.push(new DataDuration(Math.round(elapsedTime * 100) / 100));
611
- // TOTAL TIMER TIME on Object (activity, lap...)
612
- let timerTime = 0;
613
- if (isNumber(object.total_timer_time)) {
614
- timerTime = object.total_timer_time;
615
- }
616
- // If timer time is unknown then assign elapsedTime value
617
- if (!timerTime) {
618
- timerTime = elapsedTime;
619
- }
620
- stats.push(new DataTimerTime(Math.round(timerTime * 100) / 100));
621
- // Moving TIME on Object (activity, lap...)
622
- let movingTime = 0;
623
- if (object.lengths && object.lengths.length > 0) {
624
- object.lengths.forEach((lengthVal) => {
625
- if (lengthVal.length_type === 'active') {
626
- movingTime += lengthVal.total_timer_time;
627
- }
628
- });
629
- }
630
- else if (object.records && object.records.length > 0) {
631
- const speedThreshold = ActivityTypesMoving.getSpeedThreshold(activity.type);
632
- object.records.forEach((record, index) => {
633
- var _a;
634
- if ((record.speed || record.enhanced_speed) > speedThreshold) {
635
- const previousRecordTime = ((_a = object.records[index - 1]) === null || _a === void 0 ? void 0 : _a.timestamp) || object.start_time || object.records[0].timestamp;
636
- movingTime += (record.timestamp.getTime() - previousRecordTime.getTime()) / 1000;
637
- }
638
- });
639
- }
640
- if (isLap) {
641
- // In case we moved (distance > 0) & moving time is invalid, then set it to timer time value
642
- if (object.total_distance > 0 && (!movingTime || movingTime > timerTime)) {
643
- movingTime = timerTime;
644
- }
645
- }
646
- // Append moving stat only if moving time has been detected
647
- // We need that to compute total global moving time later
648
- if (movingTime > 0) {
649
- stats.push(new DataMovingTime(Math.round(movingTime * 100) / 100));
650
- }
651
- // Pause TIME on Object (activity, lap...)
652
- const pause = elapsedTime > movingTime && movingTime > 0 ? Math.round((elapsedTime - movingTime) * 100) / 100 : 0;
653
- stats.push(new DataPause(pause));
654
- const getStatValue = (obj, keys) => {
655
- for (const key of keys) {
656
- if (isNumberOrString(obj[key])) {
657
- return obj[key];
658
- }
659
- }
660
- return null;
661
- };
662
- const avgSpeed = getStatValue(object, ['enhanced_avg_speed', 'EnhancedAvgSpeed', 'avg_speed', 'AvgSpeed']);
663
- const totalDistance = getStatValue(object, ['total_distance', 'TotalDistance']);
664
- // Assign is active lap status
665
- stats.push(new DataActiveLap(!!(totalDistance || avgSpeed)));
666
- if (totalDistance !== null) {
667
- stats.push(new DataDistance(totalDistance));
668
- }
669
- else {
670
- stats.push(new DataDistance(0));
671
- }
672
- // Heart Rate
673
- if (isNumberOrString(object.avg_heart_rate)) {
674
- stats.push(new DataHeartRateAvg(object.avg_heart_rate));
675
- }
676
- if (isNumberOrString(object.min_heart_rate)) {
677
- stats.push(new DataHeartRateMin(object.min_heart_rate));
678
- }
679
- if (isNumberOrString(object.max_heart_rate)) {
680
- stats.push(new DataHeartRateMax(object.max_heart_rate));
681
- }
682
- // Cadence
683
- if (isNumberOrString(object.avg_cadence)) {
684
- stats.push(new DataCadenceAvg(object.avg_cadence));
685
- }
686
- if (isNumberOrString(object.min_cadence)) {
687
- stats.push(new DataCadenceMin(object.min_cadence));
688
- }
689
- if (isNumberOrString(object.max_cadence)) {
690
- stats.push(new DataCadenceMax(object.max_cadence));
691
- }
692
- // Power
693
- if (isNumberOrString(object.avg_power)) {
694
- stats.push(new DataPowerAvg(object.avg_power));
695
- }
696
- if (isNumberOrString(object.min_power)) {
697
- stats.push(new DataPowerMin(object.min_power));
698
- }
699
- if (isNumberOrString(object.max_power)) {
700
- stats.push(new DataPowerMax(object.max_power));
701
- }
702
- if (Number.isFinite(object.normalized_power)) {
703
- stats.push(new DataPowerNormalized(object.normalized_power));
704
- }
705
- if (Number.isFinite(object.intensity_factor)) {
706
- stats.push(new DataPowerIntensityFactor(object.intensity_factor));
707
- }
708
- if (Number.isFinite(object.training_stress_score)) {
709
- stats.push(new DataPowerTrainingStressScore(object.training_stress_score));
710
- }
711
- if (Number.isFinite(object.total_work)) {
712
- stats.push(new DataPowerWork(Math.round(object.total_work / 1000)));
713
- }
714
- if (Number.isFinite(object.avg_left_torque_effectiveness)) {
715
- stats.push(new DataPowerTorqueEffectivenessLeft(object.avg_left_torque_effectiveness));
716
- }
717
- if (Number.isFinite(object.avg_right_torque_effectiveness)) {
718
- stats.push(new DataPowerTorqueEffectivenessRight(object.avg_right_torque_effectiveness));
719
- }
720
- if (Number.isFinite(object.avg_left_pedal_smoothness)) {
721
- stats.push(new DataPowerPedalSmoothnessLeft(object.avg_left_pedal_smoothness));
722
- }
723
- if (Number.isFinite(object.avg_right_pedal_smoothness)) {
724
- stats.push(new DataPowerPedalSmoothnessRight(object.avg_right_pedal_smoothness));
725
- }
726
- // Speed
727
- if (avgSpeed !== null) {
728
- stats.push(new DataSpeedAvg(avgSpeed));
729
- }
730
- const minSpeed = getStatValue(object, ['enhanced_min_speed', 'EnhancedMinSpeed', 'min_speed', 'MinSpeed']);
731
- if (minSpeed !== null) {
732
- stats.push(new DataSpeedMin(minSpeed));
733
- }
734
- const maxSpeed = getStatValue(object, ['enhanced_max_speed', 'EnhancedMaxSpeed', 'max_speed', 'MaxSpeed']);
735
- if (maxSpeed !== null) {
736
- stats.push(new DataSpeedMax(maxSpeed));
737
- }
738
- // Temperature
739
- if (isNumberOrString(object.avg_temperature)) {
740
- stats.push(new DataTemperatureAvg(object.avg_temperature));
741
- }
742
- if (isNumberOrString(object.min_temperature)) {
743
- stats.push(new DataTemperatureMin(object.min_temperature));
744
- }
745
- if (isNumberOrString(object.max_temperature)) {
746
- stats.push(new DataTemperatureMax(object.max_temperature));
747
- }
748
- // Ascent
749
- const ascent = getStatValue(object, ['total_ascent', 'TotalAscent']);
750
- if (ascent !== null) {
751
- stats.push(new DataAscent(ascent));
752
- }
753
- // Descent
754
- const descent = getStatValue(object, ['total_descent', 'TotalDescent']);
755
- if (descent !== null) {
756
- stats.push(new DataDescent(descent));
757
- }
758
- // Calories
759
- if (isNumberOrString(object.total_calories)) {
760
- stats.push(new DataEnergy(object.total_calories));
761
- }
762
- // Total training effect = Aerobic training effect
763
- if (isNumberOrString(object.total_training_effect)) {
764
- stats.push(new DataAerobicTrainingEffect(object.total_training_effect));
765
- }
766
- // Total training anaerobic effect
767
- if (isNumberOrString(object.total_anaerobic_effect)) {
768
- stats.push(new DataAnaerobicTrainingEffect(object.total_anaerobic_effect));
769
- }
770
- // Vo2Max
771
- if (isNumberOrString(object.estimated_vo2_max)) {
772
- stats.push(new DataVO2Max(object.estimated_vo2_max));
773
- }
774
- // Peak Epoc
775
- if (isNumberOrString(object.peak_epoc)) {
776
- stats.push(new DataPeakEPOC(object.peak_epoc));
777
- }
778
- // Recovery time
779
- if (isNumberOrString(object.recovery_time)) {
780
- stats.push(new DataRecoveryTime(object.recovery_time));
781
- }
782
- // Feeling
783
- if (isNumberOrString(object.feeling)) {
784
- stats.push(new DataFeeling(object.feeling));
785
- }
786
- // Pool length
787
- if (isNumberOrString(object.pool_length)) {
788
- let poolLength = object.pool_length;
789
- if (object.pool_length_unit) {
790
- poolLength = object.pool_length_unit.match(/metric/i) ? object.pool_length : object.pool_length * 0.9144; // Convert to meters from yards when not metric
791
- }
792
- stats.push(new DataPoolLength(poolLength));
793
- }
794
- // Average SWOLF in 25m and 50m pool
795
- if ((activity.type === ActivityTypes.Swimming || activity.type === ActivityTypes.OpenWaterSwimming) &&
796
- (isNumberOrString(object.avg_speed) || isNumberOrString(object.enhanced_avg_speed)) &&
797
- isNumberOrString(object.avg_cadence)) {
798
- const avgPace100m = 100 / (object.avg_speed || object.enhanced_avg_speed);
799
- if (Number.isFinite(avgPace100m) && Number.isFinite(object.avg_cadence)) {
800
- const avgCadence = object.avg_cadence;
801
- const swolf25m = ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 25);
802
- stats.push(new DataSWOLF25m(swolf25m));
803
- const swolf50m = ActivityUtilities.computeSwimSwolf(avgPace100m, avgCadence, 50);
804
- stats.push(new DataSWOLF50m(swolf50m));
805
- }
806
- }
807
- // Active lengths
808
- if (isNumberOrString(object.num_active_lengths)) {
809
- stats.push(new DataActiveLengths(object.num_active_lengths));
810
- }
811
- // Total cycle
812
- if (isNumberOrString(object.total_cycles)) {
813
- stats.push(new DataTotalCycles(object.total_cycles));
814
- }
815
- // Description
816
- if (isNumberOrString(object.description)) {
817
- stats.push(new DataDescription(object.description));
818
- }
819
- // Cycling dynamics
820
- if (Number.isFinite(object.time_standing)) {
821
- const standingTime = Math.round(object.time_standing);
822
- stats.push(new DataCyclingStandingTime(standingTime));
823
- const seatedTime = Math.round(timerTime - standingTime);
824
- stats.push(new DataCyclingSeatedTime(seatedTime));
825
- }
826
- // Running dynamics
827
- if (Number.isFinite(object.avg_stance_time)) {
828
- stats.push(new DataStanceTime(object.avg_stance_time));
829
- }
830
- if (Number.isFinite(object.avg_vertical_oscillation)) {
831
- stats.push(new DataVerticalOscillation(object.avg_vertical_oscillation));
832
- }
833
- if (Number.isFinite(object.avg_vertical_ratio)) {
834
- stats.push(new DataVerticalRatio(object.avg_vertical_ratio));
835
- }
836
- if (Number.isFinite(object.avg_step_length)) {
837
- const avgStrideLengthMeters = object.avg_step_length / 1000;
838
- stats.push(new DataAvgStrideLength(Math.round(avgStrideLengthMeters * 100) / 100));
839
- }
840
- return stats;
841
- }
842
- static getCreatorFromFitDataObject(fitDataObject) {
843
- const toStartCase = (str) => {
844
- return str.replace(/\w\S*/g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
845
- };
846
- const formatDeviceName = (manufacturer, productName, recognizedName, recognizedBrand, isDevelopment = false) => {
847
- let name = '';
848
- if (recognizedBrand && recognizedName) {
849
- name = `${toStartCase(recognizedBrand)} ${recognizedName}`;
850
- }
851
- else if (recognizedBrand && !recognizedName && productName) {
852
- if (productName.match(new RegExp(`${recognizedBrand}`, 'gi'))) {
853
- productName = productName.replace(new RegExp(`${recognizedBrand}`, 'gi'), '').trim();
854
- }
855
- name = `${toStartCase(recognizedBrand)} ${productName}`;
856
- }
857
- else if (recognizedBrand && !recognizedName && !productName) {
858
- name = `${toStartCase(recognizedBrand)}`;
859
- }
860
- else if (manufacturer && !recognizedBrand && !recognizedName && !productName && !isDevelopment) {
861
- const formattedManufacturer = manufacturer.replace(new RegExp('[-_]', 'gi'), ' ').trim();
862
- name = `${toStartCase(formattedManufacturer)}`;
863
- }
864
- else if (!recognizedBrand && recognizedName) {
865
- name = `${recognizedName}`;
866
- }
867
- else {
868
- name = 'Unknown';
869
- }
870
- return name;
871
- };
872
- let creator;
873
- let recognizedName = null;
874
- const manufacturer = fitDataObject.file_ids[0].manufacturer;
875
- const productId = fitDataObject.file_ids[0].product || null;
876
- const productName = fitDataObject.file_ids[0].product_name || null;
877
- switch (manufacturer) {
878
- case 'suunto': {
879
- recognizedName = ImporterFitSuuntoDeviceNames[productId];
880
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Suunto'), productId);
881
- break;
882
- }
883
- case 'coros': {
884
- recognizedName = ImporterFitCorosDeviceNames[productId];
885
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Coros'), productId);
886
- break;
887
- }
888
- case 'garmin': {
889
- recognizedName = GarminProfileMapper.getDeviceName(productId);
890
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Garmin'), productId);
891
- break;
892
- }
893
- case 'wahoo_fitness': {
894
- recognizedName = ImporterFitWahooDeviceNames[productId];
895
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Wahoo'), productId);
896
- break;
897
- }
898
- case 'hammerhead': {
899
- recognizedName = ImporterFitHammerheadDeviceNames[productId];
900
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Hammerhead'), productId);
901
- break;
902
- }
903
- case 'lezyne': {
904
- recognizedName = ImporterFitLezyneDeviceNames[productId];
905
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Lezyne'), productId);
906
- break;
907
- }
908
- case 'magellan': {
909
- recognizedName = ImporterFitMagellanDeviceNames[productId];
910
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Magellan'), productId);
911
- break;
912
- }
913
- case 'saris': {
914
- recognizedName = ImporterFitSarisDeviceNames[productId];
915
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Saris'), productId);
916
- break;
917
- }
918
- case 'srm': {
919
- recognizedName = ImporterFitSrmDeviceNames[productId];
920
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'SRM'), productId);
921
- break;
922
- }
923
- case 'zwift': {
924
- recognizedName = 'Zwift';
925
- creator = new Creator(recognizedName);
926
- break;
927
- }
928
- case 'virtualtraining': {
929
- recognizedName = 'Rouvy';
930
- creator = new Creator(recognizedName);
931
- break;
932
- }
933
- case 'the_sufferfest': {
934
- recognizedName = `Wahoo SYSTM`;
935
- creator = new Creator(recognizedName, productId);
936
- break;
937
- }
938
- case 'stryd': {
939
- recognizedName = `Stryd`;
940
- creator = new Creator(recognizedName, productId, fitDataObject.file_creator.software_version, fitDataObject.file_creator.hardware_version, fitDataObject.file_ids[0].serial_number);
941
- break;
942
- }
943
- case 'development': {
944
- recognizedName = ImporterFitDevelopmentDeviceNames[productId];
945
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, null, true), productId);
946
- creator.isRecognized = typeof recognizedName === 'string' || recognizedName === null;
947
- break;
948
- }
949
- default: {
950
- // Try to find if it's a numeric Garmin mapping that was missed
951
- const manufacturerName = typeof manufacturer === 'number' ? GarminProfileMapper.getManufacturerName(manufacturer) : manufacturer;
952
- if (manufacturerName === 'garmin') {
953
- recognizedName = GarminProfileMapper.getDeviceName(productId);
954
- }
955
- creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, manufacturerName === 'garmin' ? 'Garmin' : null), productId);
956
- }
957
- }
958
- creator.manufacturer = manufacturer;
959
- creator.isRecognized = creator.isRecognized || !!recognizedName;
960
- if (fitDataObject.file_creator && isNumberOrString(fitDataObject.file_creator.hardware_version)) {
961
- creator.hwInfo = String(fitDataObject.file_creator.hardware_version);
962
- }
963
- if (fitDataObject.file_creator && isNumberOrString(fitDataObject.file_creator.software_version)) {
964
- creator.swInfo = String(fitDataObject.file_creator.software_version);
965
- }
966
- else if (fitDataObject.device_info && isNumberOrString(fitDataObject.device_info.software_version)) {
967
- creator.swInfo = String(fitDataObject.device_info.software_version);
968
- }
969
- if (fitDataObject.file_ids[0] && isNumberOrString(fitDataObject.file_ids[0].serial_number)) {
970
- creator.serialNumber = fitDataObject.file_ids[0].serial_number;
971
- }
972
- // If creator name is a number ONLY (e.g. product number), then flag it as 'Unknown'
973
- if (Number.isFinite(creator.name) || creator.name.match(/^\d+$/)) {
974
- creator.name = `Unknown`;
975
- }
976
- return creator;
977
- }
978
- }