openwferu 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/{README → README.txt} +16 -13
  2. data/bin/validate-workflow.rb +46 -22
  3. data/examples/README.txt +8 -0
  4. data/examples/homeworkreview.rb +66 -0
  5. data/examples/quotereporter.rb +154 -0
  6. data/lib/{openwferu.rb → openwfe.rb} +6 -8
  7. data/lib/{ru → openwfe}/contextual.rb +11 -3
  8. data/lib/{ru → openwfe/engine}/engine.rb +50 -36
  9. data/lib/{ru/participant.rb → openwfe/engine/file_persisted_engine.rb} +21 -22
  10. data/lib/openwfe/expool/expressionpool.rb +534 -0
  11. data/lib/openwfe/expool/expstorage.rb +184 -0
  12. data/lib/openwfe/expool/journalexpstorage.rb +312 -0
  13. data/lib/openwfe/expool/yamlexpstorage.rb +127 -0
  14. data/lib/{ru → openwfe/expressions}/environment.rb +19 -14
  15. data/lib/{ru → openwfe/expressions}/expressionmap.rb +48 -21
  16. data/lib/{ru → openwfe/expressions}/fe_concurrence.rb +111 -35
  17. data/lib/openwfe/expressions/fe_cursor.rb +236 -0
  18. data/lib/{ru → openwfe/expressions}/fe_define.rb +5 -5
  19. data/lib/openwfe/expressions/fe_fqv.rb +99 -0
  20. data/lib/openwfe/expressions/fe_iterator.rb +182 -0
  21. data/lib/{ru/fe_misc.rb → openwfe/expressions/fe_losfor.rb} +14 -56
  22. data/lib/openwfe/expressions/fe_misc.rb +102 -0
  23. data/lib/{ru → openwfe/expressions}/fe_participant.rb +25 -14
  24. data/lib/{ru → openwfe/expressions}/fe_raw.rb +39 -75
  25. data/lib/{ru/fe_base.rb → openwfe/expressions/fe_sequence.rb} +40 -35
  26. data/lib/{ru → openwfe/expressions}/fe_subprocess.rb +30 -14
  27. data/lib/{ru → openwfe/expressions}/fe_time.rb +59 -31
  28. data/lib/{ru → openwfe/expressions}/fe_utils.rb +42 -26
  29. data/lib/{ru → openwfe/expressions}/fe_value.rb +20 -14
  30. data/lib/openwfe/expressions/flowexpression.rb +434 -0
  31. data/lib/openwfe/expressions/raw_prog.rb +391 -0
  32. data/lib/openwfe/expressions/raw_xml.rb +128 -0
  33. data/lib/openwfe/flowexpressionid.rb +148 -0
  34. data/lib/{ru → openwfe}/logging.rb +10 -6
  35. data/lib/{osocket.rb → openwfe/osocket.rb} +36 -35
  36. data/lib/{otime.rb → openwfe/otime.rb} +71 -21
  37. data/lib/openwfe/participants/atomparticipants.rb +144 -0
  38. data/lib/openwfe/participants/enoparticipant.rb +73 -0
  39. data/lib/openwfe/participants/participant.rb +85 -0
  40. data/lib/{ru → openwfe/participants}/participantmap.rb +40 -12
  41. data/lib/{ru → openwfe/participants}/participants.rb +41 -12
  42. data/lib/openwfe/participants/soapparticipants.rb +96 -0
  43. data/lib/{controlclient.rb → openwfe/rest/controlclient.rb} +12 -13
  44. data/lib/{definitions.rb → openwfe/rest/definitions.rb} +3 -3
  45. data/lib/{exception.rb → openwfe/rest/exception.rb} +3 -3
  46. data/lib/{restclient.rb → openwfe/rest/restclient.rb} +13 -22
  47. data/lib/{worklistclient.rb → openwfe/rest/worklistclient.rb} +33 -46
  48. data/lib/openwfe/rest/xmlcodec.rb +575 -0
  49. data/lib/{ru → openwfe}/rudefinitions.rb +32 -4
  50. data/lib/{ru → openwfe}/service.rb +20 -8
  51. data/lib/openwfe/storage/yamlfilestorage.rb +159 -0
  52. data/lib/{ru → openwfe/util}/dollar.rb +10 -8
  53. data/lib/openwfe/util/lru_cache.rb +149 -0
  54. data/lib/{ru → openwfe/util}/scheduler.rb +18 -10
  55. data/lib/{ru → openwfe/util}/schedulers.rb +7 -7
  56. data/lib/{utils.rb → openwfe/utils.rb} +93 -9
  57. data/lib/openwfe/workitem.rb +366 -0
  58. data/lib/openwfe/worklist/worklists.rb +175 -0
  59. data/test/README.txt +27 -0
  60. data/test/atomtest.rb +99 -0
  61. data/test/crontest.rb +58 -0
  62. data/test/dollartest.rb +3 -3
  63. data/test/feitest.rb +42 -14
  64. data/test/file_persistence_test.rb +93 -0
  65. data/test/flowtestbase.rb +72 -26
  66. data/test/ft_0.rb +1 -97
  67. data/test/ft_0b_sequence.rb +33 -0
  68. data/test/ft_0c_testname.rb +29 -0
  69. data/test/ft_10_loop.rb +48 -0
  70. data/test/ft_11_ppd.rb +292 -0
  71. data/test/ft_12_blockparticipant.rb +45 -0
  72. data/test/ft_13_eno.rb +51 -0
  73. data/test/ft_14_subprocess.rb +90 -0
  74. data/test/ft_14b_subprocess.rb +40 -0
  75. data/test/ft_15_iterator.rb +70 -0
  76. data/test/ft_16_fqv.rb +57 -0
  77. data/test/ft_1_unset.rb +25 -1
  78. data/test/ft_2_concurrence.rb +10 -5
  79. data/test/ft_3_equals.rb +35 -1
  80. data/test/ft_4_misc.rb +16 -1
  81. data/test/ft_5_time.rb +26 -1
  82. data/test/ft_6_lambda.rb +2 -1
  83. data/test/{ft_7_losfor.rb → ft_7_lose.rb} +41 -35
  84. data/test/ft_8_forget.rb +46 -0
  85. data/test/ft_9_cursor.rb +94 -0
  86. data/test/journal_persistence_test.rb +147 -0
  87. data/test/misctest.rb +13 -9
  88. data/test/rake_ptest.rb +18 -0
  89. data/test/rake_qtest.rb +43 -0
  90. data/test/{fulltest.rb → rake_test.rb} +2 -2
  91. data/test/raw_prog_test.rb +236 -0
  92. data/test/rest_test.rb +189 -0
  93. data/test/rutest_utils.rb +1 -1
  94. data/test/timetest.rb +42 -34
  95. metadata +125 -82
  96. data/lib/codec.rb +0 -573
  97. data/lib/flowexpressionid.rb +0 -139
  98. data/lib/ru/expressionpool.rb +0 -382
  99. data/lib/ru/expressionstorage.rb +0 -99
  100. data/lib/ru/flowexpression.rb +0 -272
  101. data/lib/ru/ruutils.rb +0 -70
  102. data/lib/test.rb +0 -222
  103. data/lib/workitem.rb +0 -249
  104. data/test/quicktest.rb +0 -21
@@ -0,0 +1,148 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2005-2007, John Mettraux, OpenWFE.org
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # . Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # . Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
17
+ # used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #++
32
+ #
33
+ # $Id: workitem.rb 3555 2006-11-13 00:47:53Z jmettraux $
34
+ #
35
+
36
+ #
37
+ # "hecho en Costa Rica"
38
+ # enhanced in Japan
39
+ #
40
+ # john.mettraux@openwfe.org
41
+ #
42
+
43
+
44
+ module OpenWFE
45
+
46
+ #
47
+ # FlowExpressionId
48
+ #
49
+ class FlowExpressionId
50
+
51
+ attr_accessor \
52
+ :owfe_version, \
53
+ :engine_id, \
54
+ :initial_engine_id, \
55
+ :workflow_definition_url, \
56
+ :workflow_definition_name, \
57
+ :workflow_definition_revision, \
58
+ :workflow_instance_id, \
59
+ :expression_name, \
60
+ :expression_id
61
+
62
+ #
63
+ # overrides the classical to_s()
64
+ #
65
+ def to_s ()
66
+ return "(fei #{@owfe_version} #{@engine_id}/#{@initial_engine_id} #{@workflow_definition_url} #{@workflow_definition_name} #{@workflow_definition_revision} #{@workflow_instance_id} #{@expression_name} #{@expression_id})"
67
+ end
68
+
69
+ def hash ()
70
+ return to_s().hash()
71
+ end
72
+
73
+ def == (other)
74
+ return false if not other.kind_of?(FlowExpressionId)
75
+
76
+ @owfe_version == other.owfe_version and
77
+ @engine_id == other.engine_id and
78
+ @initial_engine_id == other.initial_engine_id and
79
+ @workflow_definition_url == other.workflow_definition_url and
80
+ @workflow_definition_name == other.workflow_definition_name and
81
+ @workflow_definition_revision == other.workflow_definition_revision and
82
+ @workflow_instance_id == other.workflow_instance_id and
83
+ @expression_name == other.expression_name and
84
+ @expression_id == other.expression_id
85
+ end
86
+
87
+ def dup
88
+ n = FlowExpressionId.new
89
+ n.owfe_version = @owfe_version.dup
90
+ n.engine_id = @engine_id.dup
91
+ n.initial_engine_id = @initial_engine_id.dup
92
+ n.workflow_definition_url = @workflow_definition_url.dup
93
+ n.workflow_definition_name = @workflow_definition_name.dup
94
+ n.workflow_definition_revision = @workflow_definition_revision.dup
95
+ n.workflow_instance_id = @workflow_instance_id.dup
96
+ n.expression_name = @expression_name.dup
97
+ n.expression_id = @expression_id.dup
98
+ return n
99
+ end
100
+
101
+ alias eql? ==
102
+
103
+ alias to_debug_s to_s
104
+ #def to_debug_s
105
+ # "#{to_s} (h#{hash}) (i#{object_id})"
106
+ #end
107
+
108
+ #
109
+ # Returns the workflow instance id without any subflow indices.
110
+ # For example, if the wfid is "1234.0.1", this method will
111
+ # return "1234".
112
+ #
113
+ def parent_workflow_instance_id
114
+ i = workflow_instance_id.index(".")
115
+ return workflow_instance_id if not i
116
+ #return workflow_instance_id[0..i]
117
+ return workflow_instance_id[0..i-1]
118
+ end
119
+
120
+ #
121
+ # This class method parses a string into a FlowExpressionId instance
122
+ #
123
+ def FlowExpressionId.to_fei (string)
124
+
125
+ fei = FlowExpressionId.new()
126
+
127
+ ss = string.split(" ")
128
+ #puts "\n#{ss}"
129
+
130
+ fei.owfe_version = ss[1]
131
+
132
+ ssRawEngineId = ss[2].split("/")
133
+ fei.engine_id= ssRawEngineId[0]
134
+ fei.initial_engine_id= ssRawEngineId[1]
135
+
136
+ fei.workflow_definition_url = ss[3]
137
+ fei.workflow_definition_name = ss[4]
138
+ fei.workflow_definition_revision = ss[5]
139
+ fei.workflow_instance_id = ss[6]
140
+ fei.expression_name = ss[7]
141
+ fei.expression_id = ss[8][0..-2]
142
+
143
+ return fei
144
+ end
145
+ end
146
+
147
+ end
148
+
@@ -1,6 +1,6 @@
1
1
  #
2
- #<tt>
3
- # Copyright (c) 2006, John Mettraux, OpenWFE.org
2
+ #--
3
+ # Copyright (c) 2006-2007, John Mettraux, OpenWFE.org
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
28
28
  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
29
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
- #</tt>
31
+ #++
32
32
  #
33
33
  # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
34
  #
@@ -40,10 +40,14 @@
40
40
  #
41
41
 
42
42
  require 'logger'
43
- require 'ru/rudefinitions'
43
+ require 'openwfe/rudefinitions'
44
44
 
45
- module OpenWFEru
46
45
 
46
+ module OpenWFE
47
+
48
+ #
49
+ # A Mixin for adding logging method to any class
50
+ #
47
51
  module Logging
48
52
 
49
53
  def init_default_logging (filename)
@@ -74,7 +78,7 @@ module OpenWFEru
74
78
  end
75
79
 
76
80
  def who
77
- if respond_to?(:service_name)
81
+ if respond_to? :service_name
78
82
  "#{self.class} '#{self.service_name}'"
79
83
  else
80
84
  "#{self.class}"
@@ -1,6 +1,6 @@
1
1
  #
2
- #<tt>
3
- # Copyright (c) 2006, John Mettraux, OpenWFE.org
2
+ #--
3
+ # Copyright (c) 2006-2007, John Mettraux, OpenWFE.org
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -28,13 +28,14 @@
28
28
  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
29
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
- #</tt>
31
+ #++
32
32
  #
33
33
  # $Id: codec.rb 2515 2006-04-26 18:38:39Z jmettraux $
34
34
  #
35
35
 
36
36
  require 'socket'
37
- require 'codec'
37
+ require 'xmlcodec'
38
+
38
39
 
39
40
  module OpenWFE
40
41
 
@@ -82,11 +83,14 @@ module OpenWFE
82
83
  end
83
84
 
84
85
  #
85
- # dispatches a workitem over TCP
86
+ # Dispatches a workitem over TCP, the workitem will be
87
+ # encoded with XML
88
+ # The default encode_method is
86
89
  #
87
- def OpenWFE.dispatchWorkitem (host, port, workitem)
90
+ def OpenWFE.dispatch_workitem (host, port, workitem)
91
+
92
+ sXml = OpenWFE.xml_encode(workitem)
88
93
 
89
- sXml = OpenWFE.encode(workitem)
90
94
  socket = TCPSocket.new(host, port)
91
95
  socket.puts "xmlCoder #{sXml.length}"
92
96
  socket.puts
@@ -103,38 +107,35 @@ module OpenWFE
103
107
  #puts "dispatch() reply is >#{reply}<"
104
108
  end
105
109
 
106
- class OwfeHook
107
- end
108
-
109
110
  end
110
111
 
111
112
 
112
113
  #
113
114
  # some test code
114
115
 
115
- sl = OpenWFE::SocketListener.new('127.0.0.1', 7010)
116
-
117
- puts "..ready.."
118
-
119
- sl.listen do |workitem|
120
-
121
- #puts workitem
122
- #next
123
-
124
- puts workitem.flowExpressionId
125
- puts "...history length : #{workitem.history.length}"
126
-
127
- #puts workitem.history
128
- workitem.history.each do |hi|
129
- puts ".....hi = '#{hi.text}' #{hi.date}"
130
- end
131
-
132
- #hi = OpenWFE::HistoryItem.new
133
- #hi.author = 'osocket.rb'
134
- #workitem.history.push(hi)
135
-
136
- workitem.attributes['ruby?'] = 'yes'
137
-
138
- OpenWFE.dispatchWorkitem('127.0.0.1', 7007, workitem)
139
- end
116
+ #sl = OpenWFE::SocketListener.new('127.0.0.1', 7010)
117
+ #
118
+ #puts "..ready.."
119
+ #
120
+ #sl.listen do |workitem|
121
+ #
122
+ # #puts workitem
123
+ # #next
124
+ #
125
+ # puts workitem.flow_expression_id
126
+ # puts "...history length : #{workitem.history.length}"
127
+ #
128
+ # #puts workitem.history
129
+ # workitem.history.each do |hi|
130
+ # puts ".....hi = '#{hi.text}' #{hi.date}"
131
+ # end
132
+ #
133
+ # #hi = OpenWFE::HistoryItem.new
134
+ # #hi.author = 'osocket.rb'
135
+ # #workitem.history.push(hi)
136
+ #
137
+ # workitem.attributes['ruby?'] = 'yes'
138
+ #
139
+ # OpenWFE.dispatch_workitem('127.0.0.1', 7007, workitem)
140
+ #end
140
141
 
@@ -1,6 +1,6 @@
1
1
  #
2
- #<tt>
3
- # Copyright (c) 2005-2006, John Mettraux, OpenWFE.org
2
+ #--
3
+ # Copyright (c) 2005-2007, John Mettraux, OpenWFE.org
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
28
28
  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
29
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
- #</tt>
31
+ #++
32
32
  #
33
33
  # $Id: otime.rb 3509 2006-10-21 12:00:52Z jmettraux $
34
34
  #
@@ -39,12 +39,13 @@
39
39
  # john.mettraux@openwfe.org
40
40
  #
41
41
 
42
- require 'parsedate'
42
+ require 'date'
43
+ #require 'parsedate'
43
44
 
44
45
 
45
46
  module OpenWFE
46
47
 
47
- TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
48
+ #TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
48
49
 
49
50
  #
50
51
  # Returns the current time as an ISO date string
@@ -53,35 +54,42 @@ module OpenWFE
53
54
  return to_iso_date(Time.new())
54
55
  end
55
56
 
56
- def OpenWFE.to_iso_date (date)
57
+ def OpenWFE.to_iso8601_date (date)
57
58
 
58
- if date.kind_of?(Float)
59
- date = Time.at(date)
59
+ if date.kind_of? Float
60
+ date = to_datetime(Time.at(date))
61
+ elsif date.kind_of? Time
62
+ date = to_datetime(date)
63
+ elsif not date.kind_of? Date
64
+ date = DateTime.parse(date)
60
65
  end
61
66
 
62
- s = date.getutc().strftime(TIME_FORMAT)
63
- o = date.utc_offset / 3600
64
- o = o.to_s() + "00"
65
- o = "0" + o if o.length < 4
66
- o = "+" + o unless o[0..1] == '-'
67
- return s + " " + o.to_s()
67
+ s = date.to_s
68
+ s[10] = " "
69
+
70
+ return s
68
71
  end
69
72
 
70
73
  #
71
- # Returns a Ruby time
74
+ # the old method we used to generate our ISO datetime strings
72
75
  #
73
- def OpenWFE.toRubyTime (isoDate)
76
+ def OpenWFE.time_to_iso8601_date (time)
77
+
78
+ s = time.getutc().strftime(TIME_FORMAT)
79
+ o = time.utc_offset / 3600
80
+ o = o.to_s + "00"
81
+ o = "0" + o if o.length < 4
82
+ o = "+" + o unless o[0..1] == '-'
74
83
 
75
- res = ParseDate.parsedate(isoDate)
76
- return Time.local(*res)
84
+ s + " " + o.to_s
77
85
  end
78
86
 
79
87
  #
80
- # An Ruby-friendly alias for toRubyTime()
88
+ # Returns a Ruby time
81
89
  #
82
90
  def OpenWFE.to_ruby_time (iso_date)
83
91
 
84
- return toRubyTime(iso_date)
92
+ return DateTime.parse(iso_date)
85
93
  end
86
94
 
87
95
  #def OpenWFE.parse_date (date)
@@ -91,6 +99,7 @@ module OpenWFE
91
99
  # equivalent to java.lang.System.currentTimeMillis()
92
100
  #
93
101
  def OpenWFE.current_time_millis ()
102
+
94
103
  t = Time.new()
95
104
  t = t.to_f * 1000
96
105
  return t.to_i
@@ -122,7 +131,7 @@ module OpenWFE
122
131
 
123
132
  if index >= string.length
124
133
  if number.length > 0
125
- result = result + (Integer(number) / 1000)
134
+ result = result + (Float(number) / 1000.0)
126
135
  end
127
136
  break
128
137
  end
@@ -157,6 +166,47 @@ module OpenWFE
157
166
  return (c >= "0" and c <= "9")
158
167
  end
159
168
 
169
+ #
170
+ # conversion methods between Date[Time] and Time
171
+
172
+ #
173
+ # Ruby Cookbook 1st edition p.111
174
+ # http://www.oreilly.com/catalog/rubyckbk/
175
+ # a must
176
+ #
177
+
178
+ #
179
+ # converts a Time instance to a DateTime one
180
+ #
181
+ def OpenWFE.to_datetime (time)
182
+
183
+ s = time.sec + Rational(time.usec, 10**6)
184
+ o = Rational(time.utc_offset, 3600 * 24)
185
+
186
+ begin
187
+ return DateTime.new(
188
+ time.year, time.month, time.day, time.hour, time.min, s, o)
189
+ rescue Exception => e
190
+ puts \
191
+ "\n Date.new() problem. Params :"+
192
+ "\n....y:#{time.year} M:#{time.month} d:#{time.day} "+
193
+ "h:#{time.hour} m:#{time.min} s:#{s} o:#{o}"
194
+ end
195
+ end
196
+
197
+ def OpenWFE.to_gm_time (dtime)
198
+ to_ttime(dtime.new_offset, :gm)
199
+ end
200
+
201
+ def OpenWFE.to_local_time (dtime)
202
+ to_ttime(dtime.new_offset(DateTime.now.offset-offset), :local)
203
+ end
204
+
205
+ def to_ttime (d, method)
206
+ usec = (d.sec_fraction * 3600 * 24 * (10**6)).to_i
207
+ Time.send(method, d.year, d.month, d.day, d.hour, d.min, d.sec, usec)
208
+ end
209
+
160
210
  protected
161
211
 
162
212
  DURATIONS = {