fit4ruby 3.5.0 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/fit4ruby.gemspec +2 -2
- data/lib/fit4ruby/Activity.rb +94 -55
- data/lib/fit4ruby/BDFieldNameTranslator.rb +36 -0
- data/lib/fit4ruby/DeviceInfo.rb +37 -0
- data/lib/fit4ruby/FDR_DevField_Extension.rb +81 -0
- data/lib/fit4ruby/FieldDescription.rb +26 -8
- data/lib/fit4ruby/FileId.rb +2 -1
- data/lib/fit4ruby/FitDataRecord.rb +85 -32
- data/lib/fit4ruby/FitDefinition.rb +11 -4
- data/lib/fit4ruby/FitDefinitionField.rb +6 -6
- data/lib/fit4ruby/FitDefinitionFieldBase.rb +15 -6
- data/lib/fit4ruby/FitDeveloperDataFieldDefinition.rb +1 -1
- data/lib/fit4ruby/FitFile.rb +2 -0
- data/lib/fit4ruby/FitMessageRecord.rb +26 -21
- data/lib/fit4ruby/FitRecord.rb +2 -1
- data/lib/fit4ruby/FitTypeDefs.rb +2 -2
- data/lib/fit4ruby/GlobalFitDictionaries.rb +366 -23
- data/lib/fit4ruby/GlobalFitMessage.rb +84 -14
- data/lib/fit4ruby/GlobalFitMessages.rb +83 -3
- data/lib/fit4ruby/Lap.rb +10 -1
- data/lib/fit4ruby/Record.rb +11 -2
- data/lib/fit4ruby/version.rb +1 -1
- data/spec/FitFile_spec.rb +198 -100
- metadata +11 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f0a74c755c07cbbcfd9b17b9efeb16a62696fd9076c9ece178e00e51b3ce075
|
4
|
+
data.tar.gz: 81ee48cea068828a6ad08c5f4f274270ec96179159e585ecc9068eccbf1be3a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f140497b1f269075e912da5988238db3a279ef5baf20e4ce29f3b960307c3b87a4ada116283f17f5965a7e0e25e9b3e5bcdce7306b14ae49cb16d837692b239
|
7
|
+
data.tar.gz: 829a3ff7cee37f26218915d8370a0dd44fe6c24152c634f073fb0d25a543c3e50783188fe81f6d5cbbb00af42974eba1aed51f59ee25a108718773b7a65f8ad8
|
data/Gemfile.lock
CHANGED
data/fit4ruby.gemspec
CHANGED
@@ -24,9 +24,9 @@ EOT
|
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
spec.required_ruby_version = '>=2.0'
|
26
26
|
|
27
|
-
spec.add_dependency('bindata', '
|
27
|
+
spec.add_dependency('bindata', '~>2.4.8')
|
28
28
|
spec.add_development_dependency('yard', '~>0.9.20')
|
29
|
-
spec.add_development_dependency('rake', '~>0.
|
29
|
+
spec.add_development_dependency('rake', '~>13.0.3')
|
30
30
|
spec.add_development_dependency('bundler', '>=1.6.4')
|
31
31
|
spec.add_development_dependency('rspec', '>=3.8')
|
32
32
|
spec.add_development_dependency('pry', '>=0.12')
|
data/lib/fit4ruby/Activity.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = Activity.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2015, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -33,45 +33,65 @@ require 'fit4ruby/PersonalRecords'
|
|
33
33
|
|
34
34
|
module Fit4Ruby
|
35
35
|
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
36
|
+
# Activity files are arguably the most common type of FIT file. The Activity
|
37
|
+
# class represents the top-level structure of an activity FIT file.
|
38
|
+
# It holds references to all other data structures. Each of the objects it
|
39
|
+
# references are direct equivalents of the message record structures used in
|
40
|
+
# the FIT file.
|
39
41
|
class Activity < FitDataRecord
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
# These symbols are a complete list of all the sub-sections that an
|
44
|
+
# activity FIT file may contain. This list is used to generate accessors,
|
45
|
+
# instance variables and other sections of code. Some are just simple
|
46
|
+
# instance variables, but the majority can appear multiple times and hence
|
47
|
+
# are stored in an Array.
|
48
|
+
FILE_SECTIONS = [
|
49
|
+
:file_id,
|
50
|
+
:file_creator,
|
51
|
+
:events,
|
52
|
+
:device_infos,
|
53
|
+
:data_sources,
|
54
|
+
:epo_data,
|
55
|
+
:user_profiles,
|
56
|
+
:user_data,
|
57
|
+
:sensor_settings,
|
58
|
+
:developer_data_ids,
|
59
|
+
:field_descriptions,
|
60
|
+
:records,
|
61
|
+
:hrv,
|
62
|
+
:laps,
|
63
|
+
:lengths,
|
64
|
+
:heart_rate_zones,
|
65
|
+
:physiological_metrics,
|
66
|
+
:sessions,
|
67
|
+
:personal_records
|
68
|
+
]
|
69
|
+
|
70
|
+
attr_accessor *FILE_SECTIONS
|
46
71
|
|
47
72
|
# Create a new Activity object.
|
48
73
|
# @param field_values [Hash] A Hash that provides initial values for
|
49
74
|
# certain fields of the FitDataRecord.
|
50
75
|
def initialize(field_values = {})
|
51
76
|
super('activity')
|
52
|
-
@meta_field_units['total_gps_distance'] = 'm'
|
53
|
-
@num_sessions = 0
|
54
77
|
|
55
|
-
|
56
|
-
|
57
|
-
|
78
|
+
# The variables hold references to other parts of the FIT file. These
|
79
|
+
# can either be direct references to a certain FIT file section or an
|
80
|
+
# Array in case the section can appear multiple times in the FIT file.
|
81
|
+
@file_id = new_file_id()
|
82
|
+
@file_creator = new_file_creator()
|
58
83
|
@epo_data = nil
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@events = []
|
67
|
-
@sessions = []
|
68
|
-
@laps = []
|
69
|
-
@lengths = []
|
70
|
-
@records = []
|
71
|
-
@hrv = []
|
72
|
-
@heart_rate_zones = []
|
73
|
-
@personal_records = []
|
84
|
+
# Initialize the remaining variables as empty Array.
|
85
|
+
FILE_SECTIONS.each do |fs|
|
86
|
+
ivar_name = '@' + fs.to_s
|
87
|
+
unless instance_variable_defined?(ivar_name)
|
88
|
+
instance_variable_set(ivar_name, [])
|
89
|
+
end
|
90
|
+
end
|
74
91
|
|
92
|
+
# The following variables hold derived or auxilliary information that
|
93
|
+
# are not directly part of the FIT file.
|
94
|
+
@meta_field_units['total_gps_distance'] = 'm'
|
75
95
|
@cur_session_laps = []
|
76
96
|
|
77
97
|
@cur_lap_records = []
|
@@ -99,11 +119,6 @@ module Fit4Ruby
|
|
99
119
|
end
|
100
120
|
@device_infos.each.with_index { |d, index| d.check(index) }
|
101
121
|
@sensor_settings.each.with_index { |s, index| s.check(index) }
|
102
|
-
unless @num_sessions == @sessions.count
|
103
|
-
Log.fatal "Activity record requires #{@num_sessions}, but "
|
104
|
-
"#{@sessions.length} session records were found in the "
|
105
|
-
"FIT file."
|
106
|
-
end
|
107
122
|
|
108
123
|
# Records must have consecutively growing timestamps and distances.
|
109
124
|
ts = Time.parse('1989-12-31')
|
@@ -308,13 +323,17 @@ module Fit4Ruby
|
|
308
323
|
def write(io, id_mapper)
|
309
324
|
@file_id.write(io, id_mapper)
|
310
325
|
@file_creator.write(io, id_mapper)
|
326
|
+
@epo_data.write(io, id_mapper) if @epo_data
|
311
327
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
328
|
+
ary_ivars = []
|
329
|
+
FILE_SECTIONS.each do |fs|
|
330
|
+
ivar_name = '@' + fs.to_s
|
331
|
+
if (ivar = instance_variable_get(ivar_name)) && ivar.respond_to?(:sort)
|
332
|
+
ary_ivars += ivar
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
ary_ivars.sort.each do |s|
|
318
337
|
s.write(io, id_mapper)
|
319
338
|
end
|
320
339
|
super
|
@@ -464,18 +483,17 @@ module Fit4Ruby
|
|
464
483
|
# @return [TrueClass/FalseClass] true if both Activities are equal,
|
465
484
|
# otherwise false.
|
466
485
|
def ==(a)
|
467
|
-
super(a)
|
468
|
-
|
469
|
-
|
470
|
-
@
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
@sessions == a.sessions && personal_records == a.personal_records
|
486
|
+
return false unless super(a)
|
487
|
+
|
488
|
+
FILE_SECTIONS.each do |fs|
|
489
|
+
ivar_name = '@' + fs.to_s
|
490
|
+
ivar = instance_variable_get(ivar_name)
|
491
|
+
a_ivar = a.instance_variable_get(ivar_name)
|
492
|
+
|
493
|
+
return false unless ivar == a_ivar
|
494
|
+
end
|
495
|
+
|
496
|
+
true
|
479
497
|
end
|
480
498
|
|
481
499
|
# Create a new FitDataRecord.
|
@@ -521,7 +539,6 @@ module Fit4Ruby
|
|
521
539
|
# Ensure that all previous records have been assigned to a lap.
|
522
540
|
record = create_new_lap(lap_field_values)
|
523
541
|
end
|
524
|
-
@num_sessions += 1
|
525
542
|
@sessions << (record = Session.new(@cur_session_laps, @lap_counter,
|
526
543
|
field_values))
|
527
544
|
@cur_session_laps = []
|
@@ -530,7 +547,7 @@ module Fit4Ruby
|
|
530
547
|
when 'length'
|
531
548
|
record = create_new_length(field_values)
|
532
549
|
when 'record'
|
533
|
-
record = Record.new(field_values)
|
550
|
+
record = Record.new(self, field_values)
|
534
551
|
@cur_lap_records << record
|
535
552
|
@cur_length_records << record
|
536
553
|
@records << record
|
@@ -547,10 +564,31 @@ module Fit4Ruby
|
|
547
564
|
record
|
548
565
|
end
|
549
566
|
|
567
|
+
def export
|
568
|
+
# Collect all records in a consistent order.
|
569
|
+
records = []
|
570
|
+
FILE_SECTIONS.each do |fs|
|
571
|
+
ivar_name = '@' + fs.to_s
|
572
|
+
ivar = instance_variable_get(ivar_name)
|
573
|
+
|
574
|
+
next unless ivar
|
575
|
+
|
576
|
+
if ivar.respond_to?(:sort) and ivar.respond_to?(:empty?)
|
577
|
+
records += ivar.sort unless ivar.empty?
|
578
|
+
else
|
579
|
+
records << ivar if ivar
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
records.map do |record|
|
584
|
+
record.export
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
550
588
|
private
|
551
589
|
|
552
590
|
def create_new_lap(field_values)
|
553
|
-
lap = Lap.new(@cur_lap_records, @laps.last,
|
591
|
+
lap = Lap.new(self, @cur_lap_records, @laps.last,
|
554
592
|
field_values,
|
555
593
|
@length_counter, @cur_lap_lengths)
|
556
594
|
lap.message_index = @lap_counter - 1
|
@@ -573,6 +611,7 @@ module Fit4Ruby
|
|
573
611
|
|
574
612
|
length
|
575
613
|
end
|
614
|
+
|
576
615
|
end
|
577
616
|
|
578
617
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = FitDataRecord.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
module Fit4Ruby
|
14
|
+
|
15
|
+
# Some FIT message field names conflict with BinData reserved names. We use
|
16
|
+
# this translation method to map the conflicting names to BinData compatible
|
17
|
+
# names.
|
18
|
+
module BDFieldNameTranslator
|
19
|
+
|
20
|
+
BD_DICT = {
|
21
|
+
'array' => '_array',
|
22
|
+
'type' => '_type'
|
23
|
+
}
|
24
|
+
|
25
|
+
def to_bd_field_name(name)
|
26
|
+
if (bd_name = BD_DICT[name])
|
27
|
+
return bd_name
|
28
|
+
end
|
29
|
+
|
30
|
+
name
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
data/lib/fit4ruby/DeviceInfo.rb
CHANGED
@@ -32,6 +32,43 @@ module Fit4Ruby
|
|
32
32
|
@timestamp <=> fdr.timestamp
|
33
33
|
end
|
34
34
|
|
35
|
+
def numeric_manufacturer
|
36
|
+
if @manufacturer && @manufacturer.is_a?(String)
|
37
|
+
if @manufacturer[0..17] == 'Undocumented value'
|
38
|
+
return @manufacturer[18..-1].to_i
|
39
|
+
else
|
40
|
+
return GlobalFitDictionaries['manufacturer'].
|
41
|
+
value_by_name(@manufacturer)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Log.fatal "Unexpected @manufacturer (#{@manufacturer}) value"
|
46
|
+
end
|
47
|
+
|
48
|
+
def numeric_product
|
49
|
+
# The numeric product ID must be an integer or nil. In case the
|
50
|
+
# dictionary did not contain an entry for the numeric ID in the fit file
|
51
|
+
# the @garmin_product or @product variables contain a String starting
|
52
|
+
# with 'Undocumented value ' followed by the ID.
|
53
|
+
if @garmin_product && @garmin_product.is_a?(String)
|
54
|
+
if @garmin_product[0..17] == 'Undocumented value'
|
55
|
+
return @garmin_product[18..-1].to_i
|
56
|
+
else
|
57
|
+
return GlobalFitDictionaries['garmin_product'].
|
58
|
+
value_by_name(@garmin_product)
|
59
|
+
end
|
60
|
+
elsif @product && @product.is_a?(String)
|
61
|
+
if @product[0..17] == 'Undocumented value'
|
62
|
+
return @product[18..-1].to_i
|
63
|
+
else
|
64
|
+
return GlobalFitDictionaries['product'].value_by_name(@product)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Log.fatal "Unexpected @product (#{@product}) or " +
|
69
|
+
"@garmin_product (#{@garmin_product}) values"
|
70
|
+
end
|
71
|
+
|
35
72
|
def check(index)
|
36
73
|
unless @device_index
|
37
74
|
Log.fatal 'device info record must have a device_index'
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = FDR_DevField_Extension.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
module Fit4Ruby
|
14
|
+
|
15
|
+
# This module extends FitDataRecord derived classes in case they have
|
16
|
+
# developer fields.
|
17
|
+
module FDR_DevField_Extension
|
18
|
+
|
19
|
+
def create_dev_field_instance_variables
|
20
|
+
# Create instance variables for developer fields
|
21
|
+
@dev_field_descriptions = {}
|
22
|
+
@top_level_record.field_descriptions.each do |field_description|
|
23
|
+
# Only create instance variables if the FieldDescription is for this
|
24
|
+
# message number.
|
25
|
+
if field_description.native_mesg_num == @message.number
|
26
|
+
name = field_description.full_field_name(@top_level_record.
|
27
|
+
developer_data_ids)
|
28
|
+
create_instance_variable(name)
|
29
|
+
@dev_field_descriptions[name] = field_description
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def each_developer_field
|
35
|
+
@top_level_record.field_descriptions.each do |field_description|
|
36
|
+
# Only create instance variables if the FieldDescription is for this
|
37
|
+
# message number.
|
38
|
+
if field_description.native_mesg_num == @message.number
|
39
|
+
name = field_description.full_field_name(@top_level_record.
|
40
|
+
developer_data_ids)
|
41
|
+
yield(field_description, instance_variable_get('@' + name))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_unit_by_name(name)
|
47
|
+
if /[A-Za-z_]+_[A-F0-9]{16}/ =~ name
|
48
|
+
@dev_field_descriptions[name].units
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def export
|
55
|
+
message = super
|
56
|
+
|
57
|
+
each_developer_field do |field_description, ivar|
|
58
|
+
field = field_description.message.fields_by_number[
|
59
|
+
field_description.native_field_num]
|
60
|
+
fit_value = field.native_to_fit(ivar)
|
61
|
+
unless field.is_undefined?(fit_value)
|
62
|
+
fld = {
|
63
|
+
'number' => field_description.native_field_num | 128,
|
64
|
+
'value' => field.fit_to_native(fit_value),
|
65
|
+
#'human' => field.to_human(fit_value),
|
66
|
+
'type' => field.type
|
67
|
+
}
|
68
|
+
fld['unit'] = field.opts[:unit] if field.opts[:unit]
|
69
|
+
fld['scale'] = field.opts[:scale] if field.opts[:scale]
|
70
|
+
|
71
|
+
message['fields'][field.name] = fld
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
message
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FieldDescription.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2017, 2018, 2019 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2017, 2018, 2019, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -25,6 +25,24 @@ module Fit4Ruby
|
|
25
25
|
def initialize(field_values = {})
|
26
26
|
super('field_description')
|
27
27
|
set_field_values(field_values)
|
28
|
+
|
29
|
+
@full_field_name = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def full_field_name(developer_data_ids)
|
33
|
+
return @full_field_name if @full_field_name
|
34
|
+
|
35
|
+
if @developer_data_index >=
|
36
|
+
developer_data_ids.size
|
37
|
+
Log.error "Developer data index #{@developer_data_index} is too large"
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
app_id = developer_data_ids[@developer_data_index].application_id
|
42
|
+
# Convert the byte array with the app ID into a 16 character hex string.
|
43
|
+
app_id_str = app_id.map { |i| '%02X' % i }.join('')
|
44
|
+
@full_field_name =
|
45
|
+
"#{@field_name.gsub(/[^A-Za-z0-9_]/, '_')}_#{app_id_str}"
|
28
46
|
end
|
29
47
|
|
30
48
|
def create_global_definition(fit_entity)
|
@@ -35,18 +53,18 @@ module Fit4Ruby
|
|
35
53
|
return
|
36
54
|
end
|
37
55
|
|
38
|
-
if @developer_data_index >=
|
39
|
-
fit_entity.top_level_record.developer_data_ids.size
|
40
|
-
Log.error "Developer data index #{@developer_data_index} is too large"
|
41
|
-
return
|
42
|
-
end
|
43
|
-
|
44
56
|
msg = messages[@native_mesg_num] ||
|
45
57
|
messages.message(@native_mesg_num, gfm.name)
|
46
58
|
unless (@fit_base_type_id & 0x7F) < FIT_TYPE_DEFS.size
|
47
59
|
Log.error "fit_base_type_id #{@fit_base_type_id} is too large"
|
48
60
|
return
|
49
61
|
end
|
62
|
+
|
63
|
+
# A fit file may include multiple definitions of the same field. We
|
64
|
+
# ignore all subsequent definitions.
|
65
|
+
return if msg.has_field?(full_field_name(fit_entity.top_level_record.
|
66
|
+
developer_data_ids))
|
67
|
+
|
50
68
|
options = {}
|
51
69
|
options[:scale] = @scale if @scale
|
52
70
|
options[:offset] = @offset if @offset
|
@@ -54,7 +72,7 @@ module Fit4Ruby
|
|
54
72
|
options[:unit] = @units
|
55
73
|
msg.field(@field_definition_number,
|
56
74
|
FIT_TYPE_DEFS[@fit_base_type_id & 0x7F][1],
|
57
|
-
|
75
|
+
@full_field_name, options)
|
58
76
|
end
|
59
77
|
|
60
78
|
end
|
data/lib/fit4ruby/FileId.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FileId.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -23,6 +23,7 @@ module Fit4Ruby
|
|
23
23
|
@time_created = Time.at(Time.now.to_i)
|
24
24
|
@manufacturer = 'development'
|
25
25
|
@type = 'activity'
|
26
|
+
@product = 0
|
26
27
|
|
27
28
|
set_field_values(field_values)
|
28
29
|
end
|