rspec-openhab-scripting 0.0.4-java → 0.0.7-java
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.
- checksums.yaml +4 -4
- data/lib/rspec/openhab/actions.rb +20 -0
- data/lib/rspec/openhab/api.rb +16 -3
- data/lib/rspec/openhab/dsl/imports.rb +29 -3
- data/lib/rspec/openhab/items.rb +59 -29
- data/lib/rspec/openhab/state.rb +12 -1
- data/lib/rspec/openhab/timer.rb +10 -0
- data/lib/rspec/openhab/version.rb +1 -1
- data/lib/rspec-openhab-scripting.rb +12 -7
- metadata +17 -3
- data/lib/rspec/bundler/inline.rb +0 -12
- data/lib/rspec/openhab/dsl/timers/timer.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76dfb6fa24e9d5efd4f0857cde57ae0c299f7ff5b6c16d08981fe04aa5ab3f52
|
4
|
+
data.tar.gz: b587bf33488da0f9a095eba35997ae4e615b6f8729ed11e1f8c514d1a195e7e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80961c7142353a5cd237414ed8a854a1ce33ef4fe0a32c758bf3a41921e6a3cf92e811fc635b9c72cc5e2d59cf1eb92710ad0a8cbb6cf6a357400180e8c4ba56
|
7
|
+
data.tar.gz: a3cef22e84c40c6f9780830873a0ac1c548e7076c81df9afe9d8fbe9e9bb30e9c316dc6352d329e1c7d95c0be470ebb319f2a7d2c3668c9b8462b24e7e45ebca
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module DSL
|
5
|
+
module Actions
|
6
|
+
# redefine these to do nothing so that rules won't fail
|
7
|
+
def notify(msg, email: nil) # rubocop:disable Lint/UnusedMethodArgument:
|
8
|
+
logger.debug("notify: #{msg}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def say(text, voice: nil, sink: nil, volume: nil) # rubocop:disable Lint/UnusedMethodArgument:
|
12
|
+
logger.debug("say: #{text}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def play_sound(filename, sink: nil, volume: nil) # rubocop:disable Lint/UnusedMethodArgument:
|
16
|
+
logger.debug("play_sound: #{filename}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/rspec/openhab/api.rb
CHANGED
@@ -15,12 +15,19 @@ module OpenHAB
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def version
|
18
|
-
|
19
|
-
version =
|
20
|
-
version = "#{version}-SNAPSHOT" if body.dig("runtimeInfo", "buildString")&.start_with?("Build #")
|
18
|
+
version = root_data.dig("runtimeInfo", "version")
|
19
|
+
version = "#{version}-SNAPSHOT" if root_data.dig("runtimeInfo", "buildString")&.start_with?("Build #")
|
21
20
|
version
|
22
21
|
end
|
23
22
|
|
23
|
+
def locale
|
24
|
+
root_data["locale"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def measurement_system
|
28
|
+
root_data["measurementSystem"]
|
29
|
+
end
|
30
|
+
|
24
31
|
def items
|
25
32
|
@faraday.get("items", metadata: ".*").body
|
26
33
|
end
|
@@ -30,5 +37,11 @@ module OpenHAB
|
|
30
37
|
rescue Faraday::ResourceNotFound
|
31
38
|
nil
|
32
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def root_data
|
44
|
+
@root_data ||= @faraday.get.body
|
45
|
+
end
|
33
46
|
end
|
34
47
|
end
|
@@ -34,8 +34,11 @@ module OpenHAB
|
|
34
34
|
class BundleContext
|
35
35
|
include org.osgi.framework.BundleContext
|
36
36
|
|
37
|
+
attr_reader :bundles
|
38
|
+
|
37
39
|
def initialize(event_manager)
|
38
40
|
@event_manager = event_manager
|
41
|
+
@bundles = []
|
39
42
|
end
|
40
43
|
|
41
44
|
def register_service(klass, service, _properties)
|
@@ -46,6 +49,10 @@ module OpenHAB
|
|
46
49
|
|
47
50
|
@event_manager.add_event_subscriber(service)
|
48
51
|
end
|
52
|
+
|
53
|
+
def get_service_reference(klass); end
|
54
|
+
def get_service(klass); end
|
55
|
+
def add_bundle_listener(listener); end
|
49
56
|
end
|
50
57
|
|
51
58
|
# don't depend on org.openhab.core.test
|
@@ -100,6 +107,17 @@ module OpenHAB
|
|
100
107
|
end
|
101
108
|
end
|
102
109
|
|
110
|
+
class ComponentContext
|
111
|
+
include org.osgi.service.component.ComponentContext
|
112
|
+
|
113
|
+
attr_reader :properties, :bundle_context
|
114
|
+
|
115
|
+
def initialize(bundle_context)
|
116
|
+
@properties = java.util.Hashtable.new
|
117
|
+
@bundle_context = bundle_context
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
103
121
|
# subclass to expose private fields
|
104
122
|
class EventManager < org.openhab.core.internal.events.OSGiEventManager
|
105
123
|
field_reader :typedEventFactories, :typedEventSubscribers
|
@@ -108,6 +126,8 @@ module OpenHAB
|
|
108
126
|
@imported = false
|
109
127
|
|
110
128
|
class << self
|
129
|
+
attr_accessor :api
|
130
|
+
|
111
131
|
def import_presets
|
112
132
|
return if @imported
|
113
133
|
|
@@ -127,6 +147,9 @@ module OpenHAB
|
|
127
147
|
at_exit { eh.close }
|
128
148
|
ea = EventAdmin.new(eh)
|
129
149
|
ep = org.openhab.core.internal.events.OSGiEventPublisher.new(ea)
|
150
|
+
bc = BundleContext.new(em)
|
151
|
+
cc = ComponentContext.new(bc)
|
152
|
+
cc.properties["measurementSystem"] = api.measurement_system if api
|
130
153
|
|
131
154
|
# the registries!
|
132
155
|
ss = VolatileStorageService.new
|
@@ -138,6 +161,9 @@ module OpenHAB
|
|
138
161
|
ir.managed_provider = mip = org.openhab.core.items.ManagedItemProvider.new(ss, nil)
|
139
162
|
ir.add_provider(mip)
|
140
163
|
ir.event_publisher = ep
|
164
|
+
up = org.openhab.core.internal.i18n.I18nProviderImpl.new(cc)
|
165
|
+
ir.unit_provider = up
|
166
|
+
ir.item_state_converter = org.openhab.core.internal.items.ItemStateConverterImpl.new(up)
|
141
167
|
tr = org.openhab.core.thing.internal.ThingRegistryImpl.new
|
142
168
|
mtr = org.openhab.core.automation.internal.type.ModuleTypeRegistryImpl.new
|
143
169
|
rr = org.openhab.core.automation.internal.RuleRegistryImpl.new
|
@@ -187,10 +213,11 @@ module OpenHAB
|
|
187
213
|
se = org.openhab.core.automation.module.script.rulesupport.internal
|
188
214
|
.RuleSupportScriptExtension.new(rr, srp, scmhf, scmtp, spmhf)
|
189
215
|
sew = ScriptExtensionManagerWrapper.new(se)
|
190
|
-
$se = $scriptExtension = sew
|
216
|
+
$se = $scriptExtension = sew
|
191
217
|
|
192
218
|
# need to create some singletons referencing registries
|
193
|
-
org.openhab.core.
|
219
|
+
scheduler = org.openhab.core.internal.scheduler.SchedulerImpl.new
|
220
|
+
org.openhab.core.model.script.ScriptServiceUtil.new(ir, tr, ep, nil, scheduler)
|
194
221
|
org.openhab.core.model.script.internal.engine.action.SemanticsActionService.new(ir)
|
195
222
|
|
196
223
|
# link up event bus infrastructure
|
@@ -206,7 +233,6 @@ module OpenHAB
|
|
206
233
|
em.add_event_factory(ief)
|
207
234
|
|
208
235
|
# set up the rules engine part 2
|
209
|
-
bc = BundleContext.new(em)
|
210
236
|
k = org.openhab.core.automation.internal.module.factory.CoreModuleHandlerFactory
|
211
237
|
# depending on OH version, this class is set up differently
|
212
238
|
cmhf = begin
|
data/lib/rspec/openhab/items.rb
CHANGED
@@ -3,45 +3,75 @@
|
|
3
3
|
module RSpec
|
4
4
|
module OpenHAB
|
5
5
|
module Items
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
if
|
15
|
-
|
6
|
+
class << self
|
7
|
+
def populate_items_from_api(api)
|
8
|
+
all_items = api.items
|
9
|
+
|
10
|
+
gfh = org.openhab.core.internal.items.GroupFunctionHelper.new
|
11
|
+
|
12
|
+
all_items.each do |item_json|
|
13
|
+
type, _dimension = item_json["type"].split(":")
|
14
|
+
if type == "Group"
|
15
|
+
if item_json["groupType"]
|
16
|
+
type, _dimension = item_json["groupType"].split(":")
|
17
|
+
klass = ::OpenHAB::DSL::Items.const_get(:"#{type}Item")
|
18
|
+
base_item = klass.new(item_json["name"])
|
19
|
+
end
|
20
|
+
if item_json["function"]
|
21
|
+
dto = org.openhab.core.items.dto.GroupFunctionDTO.new
|
22
|
+
dto.name = item_json.dig("function", "name")
|
23
|
+
dto.params = item_json.dig("function", "params")
|
24
|
+
function = gfh.create_group_function(dto, base_item)
|
25
|
+
end
|
26
|
+
item = GroupItem.new(item_json["name"], base_item, function)
|
27
|
+
else
|
16
28
|
klass = ::OpenHAB::DSL::Items.const_get(:"#{type}Item")
|
17
|
-
|
29
|
+
item = klass.new(item_json["name"])
|
18
30
|
end
|
19
|
-
# TODO: create group function
|
20
|
-
item = GroupItem.new(item_json["name"], base_item)
|
21
|
-
else
|
22
|
-
klass = ::OpenHAB::DSL::Items.const_get(:"#{type}Item")
|
23
|
-
item = klass.new(item_json["name"])
|
24
|
-
end
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
|
32
|
+
item.label = item_json["label"]
|
33
|
+
item_json["tags"].each do |tag|
|
34
|
+
item.add_tag(tag)
|
35
|
+
end
|
36
|
+
item_json["metadata"]&.each do |key, config|
|
37
|
+
item.meta[key] = config["value"], config["config"]
|
38
|
+
end
|
39
|
+
|
40
|
+
$ir.add(item)
|
29
41
|
end
|
30
|
-
|
31
|
-
|
42
|
+
all_items.each do |item_json| # rubocop:disable Style/CombinableLoops
|
43
|
+
item_json["groupNames"].each do |group_name|
|
44
|
+
next unless (group = $ir.get(group_name))
|
45
|
+
|
46
|
+
group.add_member($ir.get(item_json["name"]))
|
47
|
+
end
|
32
48
|
end
|
49
|
+
end
|
50
|
+
end
|
33
51
|
|
34
|
-
|
52
|
+
def autoupdate_all_items
|
53
|
+
@autoupdated_items ||= {}
|
54
|
+
$ir.for_each do |_provider, item|
|
55
|
+
@autoupdated_items[item] = item.meta.delete("autoupdate") if item.meta.key?("autoupdate")
|
35
56
|
end
|
36
|
-
|
37
|
-
item_json["groupNames"].each do |group_name|
|
38
|
-
next unless (group = $ir.get(group_name))
|
57
|
+
end
|
39
58
|
|
40
|
-
|
41
|
-
|
59
|
+
private
|
60
|
+
|
61
|
+
def restore_autoupdate_items
|
62
|
+
return unless instance_variable_defined?(:@autoupdated_items)
|
63
|
+
|
64
|
+
@autoupdated_items.each do |(item, meta)|
|
65
|
+
item.meta["autoupdate"] = meta
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
::RSpec.configure do |config|
|
70
|
+
config.include(self)
|
71
|
+
config.after do
|
72
|
+
restore_autoupdate_items
|
42
73
|
end
|
43
74
|
end
|
44
|
-
# rubocop:enable Style/GlobalVars
|
45
75
|
end
|
46
76
|
end
|
47
77
|
end
|
data/lib/rspec/openhab/state.rb
CHANGED
@@ -2,8 +2,19 @@
|
|
2
2
|
|
3
3
|
RSpec.configure do |config|
|
4
4
|
config.before(:each) do
|
5
|
-
$ir.
|
5
|
+
ep = $ir.event_publisher
|
6
|
+
|
7
|
+
# stash event publishers to avoid triggering any rules
|
8
|
+
$ir.for_each do |_provider, item|
|
9
|
+
item.event_publisher = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
$ir.for_each do |_provider, item| # rubocop:disable Style/CombinableLoops
|
6
13
|
item.state = NULL # don't use update, to avoid triggering any rules
|
7
14
|
end
|
15
|
+
ensure
|
16
|
+
$ir.for_each do |_provider, item|
|
17
|
+
item.event_publisher = ep
|
18
|
+
end
|
8
19
|
end
|
9
20
|
end
|
@@ -34,10 +34,10 @@ maven_require do
|
|
34
34
|
require "jar tech.units, indriya, 2.1.3"
|
35
35
|
|
36
36
|
require "jar org.openhab.core.bundles, org.openhab.core, #{openhab_version}"
|
37
|
-
require "jar org.openhab.core.bundles, org.openhab.core.config.core, #{openhab_version}"
|
38
37
|
require "jar org.openhab.core.bundles, org.openhab.core.automation, #{openhab_version}"
|
39
38
|
require "jar org.openhab.core.bundles, org.openhab.core.automation.module.script, #{openhab_version}"
|
40
39
|
require "jar org.openhab.core.bundles, org.openhab.core.automation.module.script.rulesupport, #{openhab_version}"
|
40
|
+
require "jar org.openhab.core.bundles, org.openhab.core.config.core, #{openhab_version}"
|
41
41
|
require "jar org.openhab.core.bundles, org.openhab.core.io.monitor, #{openhab_version}"
|
42
42
|
require "jar org.openhab.core.bundles, org.openhab.core.model.core, #{openhab_version}"
|
43
43
|
require "jar org.openhab.core.bundles, org.openhab.core.model.script, #{openhab_version}"
|
@@ -59,17 +59,16 @@ end
|
|
59
59
|
require "openhab/log/logger"
|
60
60
|
require "rspec/openhab/core/logger"
|
61
61
|
require "openhab/dsl/imports"
|
62
|
+
OpenHAB::DSL::Imports.api = api
|
62
63
|
OpenHAB::DSL::Imports.import_presets
|
63
64
|
|
64
65
|
require "openhab"
|
65
66
|
|
67
|
+
require "rspec/openhab/actions"
|
66
68
|
require "rspec/openhab/core/cron_scheduler"
|
67
69
|
|
68
|
-
# openhab-scripting uses a require_relative, so our override doesn't get used
|
69
|
-
OpenHAB::DSL.send(:remove_const, :Timer)
|
70
|
-
require_relative "rspec/openhab/dsl/timers/timer"
|
71
|
-
|
72
70
|
# RSpec additions
|
71
|
+
require "rspec/core"
|
73
72
|
require "rspec/openhab/dsl/rules/rspec"
|
74
73
|
require "rspec/openhab/state"
|
75
74
|
require "rspec/openhab/trigger"
|
@@ -78,13 +77,19 @@ require "rspec/openhab/items"
|
|
78
77
|
|
79
78
|
RSpec::OpenHAB::Items.populate_items_from_api(api)
|
80
79
|
|
80
|
+
# make bundler/inline _not_ destroy the already existing load path
|
81
|
+
module Bundler
|
82
|
+
module SharedHelpers
|
83
|
+
def clean_load_path; end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
81
87
|
# load rules files
|
82
88
|
OPENHAB_AUTOMATION_PATH = "#{org.openhab.core.OpenHAB.config_folder}/automation/jsr223/ruby/personal"
|
83
89
|
|
84
|
-
# set up some environment the rules files expect
|
85
90
|
Dir["#{OPENHAB_AUTOMATION_PATH}/*.rb"].each do |f|
|
86
91
|
load f
|
87
92
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
88
|
-
warn "Failed loading #{f}: #{e}"
|
93
|
+
warn "Failed loading #{f}: #{e.inspect}"
|
89
94
|
warn e.backtrace
|
90
95
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-openhab-scripting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '4.42'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.11'
|
75
|
+
name: rspec-core
|
76
|
+
prerelease: false
|
77
|
+
type: :runtime
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.11'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
requirement: !ruby/object:Gem::Requirement
|
71
85
|
requirements:
|
@@ -158,7 +172,7 @@ extra_rdoc_files: []
|
|
158
172
|
files:
|
159
173
|
- lib/rspec-openhab-scripting.rb
|
160
174
|
- lib/rspec-openhab-scripting_jars.rb
|
161
|
-
- lib/rspec/
|
175
|
+
- lib/rspec/openhab/actions.rb
|
162
176
|
- lib/rspec/openhab/api.rb
|
163
177
|
- lib/rspec/openhab/core/cron_scheduler.rb
|
164
178
|
- lib/rspec/openhab/core/load_path.rb
|
@@ -168,9 +182,9 @@ files:
|
|
168
182
|
- lib/rspec/openhab/core/script_handling.rb
|
169
183
|
- lib/rspec/openhab/dsl/imports.rb
|
170
184
|
- lib/rspec/openhab/dsl/rules/rspec.rb
|
171
|
-
- lib/rspec/openhab/dsl/timers/timer.rb
|
172
185
|
- lib/rspec/openhab/items.rb
|
173
186
|
- lib/rspec/openhab/state.rb
|
187
|
+
- lib/rspec/openhab/timer.rb
|
174
188
|
- lib/rspec/openhab/trigger.rb
|
175
189
|
- lib/rspec/openhab/version.rb
|
176
190
|
- lib/rspec/openhab/wait.rb
|
data/lib/rspec/bundler/inline.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Bundler
|
4
|
-
class DummyDsl
|
5
|
-
def source(*); end
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def gemfile(*, &block)
|
10
|
-
# needs to be a no-op, since we're already running in the context of bundler
|
11
|
-
Bundler::DummyDsl.new.instance_eval(&block)
|
12
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenHAB
|
4
|
-
module DSL
|
5
|
-
class Timer
|
6
|
-
#
|
7
|
-
# Create a new Timer Object
|
8
|
-
#
|
9
|
-
# @param [Duration] duration Duration until timer should fire
|
10
|
-
# @param [Block] block Block to execute when timer fires
|
11
|
-
#
|
12
|
-
def initialize(duration:, thread_locals: {}, &block) # rubocop:disable Lint/UnusedMethodArgument
|
13
|
-
@duration = duration
|
14
|
-
|
15
|
-
Timers.timer_manager.add(self)
|
16
|
-
end
|
17
|
-
|
18
|
-
def reschedule(duration = nil)
|
19
|
-
duration ||= @duration
|
20
|
-
|
21
|
-
Timers.timer_manager.add(self)
|
22
|
-
reschedule(OpenHAB::DSL.to_zdt(duration))
|
23
|
-
end
|
24
|
-
|
25
|
-
#
|
26
|
-
# Cancel timer
|
27
|
-
#
|
28
|
-
# @return [Boolean] True if cancel was successful, false otherwise
|
29
|
-
#
|
30
|
-
def cancel
|
31
|
-
Timers.timer_manager.delete(self)
|
32
|
-
end
|
33
|
-
|
34
|
-
def terminated?; end
|
35
|
-
alias_method :has_terminated, :terminated?
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def timer_block
|
40
|
-
proc do
|
41
|
-
Timers.timer_manager.delete(self)
|
42
|
-
yield(self)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
#
|
48
|
-
# Convert TemporalAmount (Duration), seconds (float, integer), and Ruby Time to ZonedDateTime
|
49
|
-
# Note: TemporalAmount is added to now
|
50
|
-
#
|
51
|
-
# @param [Object] timestamp to convert
|
52
|
-
#
|
53
|
-
# @return [ZonedDateTime]
|
54
|
-
#
|
55
|
-
def self.to_zdt(timestamp)
|
56
|
-
logger.trace("Converting #{timestamp} (#{timestamp.class}) to ZonedDateTime")
|
57
|
-
return unless timestamp
|
58
|
-
|
59
|
-
case timestamp
|
60
|
-
when Java::JavaTimeTemporal::TemporalAmount then ZonedDateTime.now.plus(timestamp)
|
61
|
-
when ZonedDateTime then timestamp
|
62
|
-
when Time then timestamp.to_java(ZonedDateTime)
|
63
|
-
else
|
64
|
-
to_zdt(seconds_to_duration(timestamp)) ||
|
65
|
-
raise(ArgumentError, "Timestamp must be a ZonedDateTime, a Duration, a Numeric, or a Time object")
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
#
|
70
|
-
# Convert numeric seconds to a Duration object
|
71
|
-
#
|
72
|
-
# @param [Float, Integer] secs The number of seconds in integer or float
|
73
|
-
#
|
74
|
-
# @return [Duration]
|
75
|
-
#
|
76
|
-
def self.seconds_to_duration(secs)
|
77
|
-
return unless secs
|
78
|
-
|
79
|
-
if secs.respond_to?(:to_f)
|
80
|
-
secs.to_f.seconds
|
81
|
-
elsif secs.respond_to?(:to_i)
|
82
|
-
secs.to_i.seconds
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|