tty-progressbar 0.17.0 → 0.18.0
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/CHANGELOG.md +32 -0
- data/LICENSE.txt +1 -1
- data/README.md +492 -126
- data/lib/tty-progressbar.rb +2 -2
- data/lib/tty/progressbar.rb +168 -68
- data/lib/tty/progressbar/configuration.rb +121 -27
- data/lib/tty/progressbar/converter.rb +16 -19
- data/lib/tty/progressbar/formats.rb +120 -0
- data/lib/tty/progressbar/formatter.rb +33 -38
- data/lib/tty/progressbar/formatter/bar.rb +74 -27
- data/lib/tty/progressbar/formatter/byte_rate.rb +6 -20
- data/lib/tty/progressbar/formatter/current.rb +4 -19
- data/lib/tty/progressbar/formatter/current_byte.rb +9 -17
- data/lib/tty/progressbar/formatter/elapsed.rb +9 -18
- data/lib/tty/progressbar/formatter/estimated.rb +14 -18
- data/lib/tty/progressbar/formatter/estimated_time.rb +37 -0
- data/lib/tty/progressbar/formatter/mean_byte.rb +6 -20
- data/lib/tty/progressbar/formatter/mean_rate.rb +6 -20
- data/lib/tty/progressbar/formatter/percent.rb +10 -16
- data/lib/tty/progressbar/formatter/rate.rb +5 -19
- data/lib/tty/progressbar/formatter/total.rb +10 -16
- data/lib/tty/progressbar/formatter/total_byte.rb +14 -18
- data/lib/tty/progressbar/formatters.rb +53 -0
- data/lib/tty/progressbar/meter.rb +2 -2
- data/lib/tty/progressbar/multi.rb +61 -21
- data/lib/tty/progressbar/pipeline.rb +13 -6
- data/lib/tty/progressbar/timer.rb +89 -0
- data/lib/tty/progressbar/version.rb +1 -1
- metadata +44 -103
- data/Rakefile +0 -8
- data/examples/color.rb +0 -18
- data/examples/failure.rb +0 -12
- data/examples/iterator.rb +0 -5
- data/examples/lazy.rb +0 -6
- data/examples/multi/main_bar.rb +0 -13
- data/examples/multi/simple.rb +0 -13
- data/examples/multi/width.rb +0 -13
- data/examples/simple.rb +0 -7
- data/examples/slow_process.rb +0 -29
- data/examples/speed.rb +0 -11
- data/examples/threaded.rb +0 -14
- data/examples/tokens.rb +0 -12
- data/examples/unicode.rb +0 -7
- data/spec/spec_helper.rb +0 -53
- data/spec/unit/advance_spec.rb +0 -25
- data/spec/unit/clear_spec.rb +0 -17
- data/spec/unit/complete_spec.rb +0 -16
- data/spec/unit/converter/to_bytes_spec.rb +0 -47
- data/spec/unit/converter/to_seconds_spec.rb +0 -15
- data/spec/unit/converter/to_time_spec.rb +0 -19
- data/spec/unit/custom_formatter_spec.rb +0 -26
- data/spec/unit/custom_token_spec.rb +0 -14
- data/spec/unit/events_spec.rb +0 -33
- data/spec/unit/finish_spec.rb +0 -15
- data/spec/unit/formatter/bar_spec.rb +0 -33
- data/spec/unit/formatter/byte_rate_spec.rb +0 -32
- data/spec/unit/formatter/current_byte_spec.rb +0 -16
- data/spec/unit/formatter/current_spec.rb +0 -14
- data/spec/unit/formatter/elapsed_spec.rb +0 -58
- data/spec/unit/formatter/estimated_spec.rb +0 -27
- data/spec/unit/formatter/mean_byte_spec.rb +0 -32
- data/spec/unit/formatter/mean_rate_spec.rb +0 -31
- data/spec/unit/formatter/percent_spec.rb +0 -16
- data/spec/unit/formatter/rate_spec.rb +0 -31
- data/spec/unit/formatter/total_byte_spec.rb +0 -16
- data/spec/unit/formatter/total_spec.rb +0 -16
- data/spec/unit/frequency_spec.rb +0 -27
- data/spec/unit/head_spec.rb +0 -32
- data/spec/unit/hide_cursor_spec.rb +0 -27
- data/spec/unit/inspect_spec.rb +0 -11
- data/spec/unit/iterate_spec.rb +0 -79
- data/spec/unit/log_spec.rb +0 -29
- data/spec/unit/meter_spec.rb +0 -70
- data/spec/unit/multi/advance_spec.rb +0 -123
- data/spec/unit/multi/events_spec.rb +0 -115
- data/spec/unit/multi/finish_spec.rb +0 -41
- data/spec/unit/multi/line_inset_spec.rb +0 -65
- data/spec/unit/multi/register_spec.rb +0 -35
- data/spec/unit/multi/reset_spec.rb +0 -28
- data/spec/unit/multi/stop_spec.rb +0 -15
- data/spec/unit/multi/width_spec.rb +0 -118
- data/spec/unit/new_spec.rb +0 -76
- data/spec/unit/pipeline_spec.rb +0 -19
- data/spec/unit/ratio_spec.rb +0 -31
- data/spec/unit/render_spec.rb +0 -25
- data/spec/unit/reset_spec.rb +0 -31
- data/spec/unit/resize_spec.rb +0 -35
- data/spec/unit/set_current_spec.rb +0 -43
- data/spec/unit/start_spec.rb +0 -14
- data/spec/unit/stop_spec.rb +0 -19
- data/spec/unit/update_spec.rb +0 -22
- data/spec/unit/width_spec.rb +0 -86
- data/tasks/console.rake +0 -9
- data/tasks/coverage.rake +0 -9
- data/tasks/spec.rake +0 -27
- data/tty-progressbar.gemspec +0 -32
@@ -1,31 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../formatter"
|
4
|
+
|
3
5
|
module TTY
|
4
6
|
class ProgressBar
|
5
7
|
# Used by {Pipeline} to format :percent token
|
6
8
|
#
|
7
9
|
# @api private
|
8
10
|
class PercentFormatter
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(progress, *args, &block)
|
12
|
-
@progress = progress
|
13
|
-
end
|
11
|
+
include TTY::ProgressBar::Formatter[/:percent\b/.freeze]
|
14
12
|
|
15
|
-
#
|
13
|
+
# Format :percent token
|
16
14
|
#
|
17
|
-
# @param [
|
15
|
+
# @param [String] value
|
16
|
+
# the value to format
|
18
17
|
#
|
19
|
-
# @
|
20
|
-
|
21
|
-
# @api private
|
22
|
-
def matches?(value)
|
23
|
-
!!(value.to_s =~ MATCHER)
|
24
|
-
end
|
25
|
-
|
26
|
-
def format(value)
|
18
|
+
# @api public
|
19
|
+
def call(value)
|
27
20
|
percent = @progress.width == 0 ? 100 : (@progress.ratio * 100).to_i
|
28
|
-
|
21
|
+
display = @progress.indeterminate? ? "-" : percent.to_s
|
22
|
+
value.gsub(matcher, "#{display}%")
|
29
23
|
end
|
30
24
|
end # PercentFormatter
|
31
25
|
end # ProgressBar
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../converter"
|
4
|
+
require_relative "../formatter"
|
4
5
|
|
5
6
|
module TTY
|
6
7
|
class ProgressBar
|
@@ -8,22 +9,7 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class RateFormatter
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(progress)
|
14
|
-
@progress = progress
|
15
|
-
end
|
16
|
-
|
17
|
-
# Determines whether this formatter is applied or not.
|
18
|
-
#
|
19
|
-
# @param [Object] value
|
20
|
-
#
|
21
|
-
# @return [Boolean]
|
22
|
-
#
|
23
|
-
# @api private
|
24
|
-
def matches?(value)
|
25
|
-
!!(value.to_s =~ MATCHER)
|
26
|
-
end
|
12
|
+
include TTY::ProgressBar::Formatter[/:rate/i.freeze]
|
27
13
|
|
28
14
|
# Format :rate token
|
29
15
|
#
|
@@ -31,9 +17,9 @@ module TTY
|
|
31
17
|
# the value being formatted
|
32
18
|
#
|
33
19
|
# @api public
|
34
|
-
def
|
20
|
+
def call(value)
|
35
21
|
formatted = Converter.to_seconds(@progress.rate)
|
36
|
-
value.gsub(
|
22
|
+
value.gsub(matcher, formatted)
|
37
23
|
end
|
38
24
|
end # RateFormatter
|
39
25
|
end # ProgressBar
|
@@ -1,30 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../formatter"
|
4
|
+
|
3
5
|
module TTY
|
4
6
|
class ProgressBar
|
5
7
|
# Used by {Pipeline} to format :total token
|
6
8
|
#
|
7
9
|
# @api private
|
8
10
|
class TotalFormatter
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(progress, *args, &block)
|
12
|
-
@progress = progress
|
13
|
-
end
|
11
|
+
include TTY::ProgressBar::Formatter[/:total\b/i.freeze]
|
14
12
|
|
15
|
-
#
|
13
|
+
# Format :total token
|
16
14
|
#
|
17
|
-
# @param [
|
15
|
+
# @param [String] value
|
16
|
+
# the value to format
|
18
17
|
#
|
19
|
-
# @
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
!!(value.to_s =~ MATCHER)
|
24
|
-
end
|
25
|
-
|
26
|
-
def format(value)
|
27
|
-
value.gsub(MATCHER, @progress.total.to_s)
|
18
|
+
# @api public
|
19
|
+
def call(value)
|
20
|
+
display = @progress.indeterminate? ? "-" : @progress.total.to_s
|
21
|
+
value.gsub(matcher, display)
|
28
22
|
end
|
29
23
|
end # TotalFormatter
|
30
24
|
end # ProgressBar
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../converter"
|
4
|
+
require_relative "../formatter"
|
4
5
|
|
5
6
|
module TTY
|
6
7
|
class ProgressBar
|
@@ -8,26 +9,21 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class TotalByteFormatter
|
11
|
-
|
12
|
+
include TTY::ProgressBar::Formatter[/:total_byte/i.freeze]
|
12
13
|
|
13
|
-
|
14
|
-
@progress = progress
|
15
|
-
end
|
16
|
-
|
17
|
-
# Determines whether this formatter is applied or not.
|
18
|
-
#
|
19
|
-
# @param [Object] value
|
14
|
+
# Format :total_byte token
|
20
15
|
#
|
21
|
-
# @
|
16
|
+
# @param [String] value
|
17
|
+
# the value to format
|
22
18
|
#
|
23
|
-
# @api
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
value.gsub(
|
19
|
+
# @api public
|
20
|
+
def call(value)
|
21
|
+
bytes = if @progress.indeterminate?
|
22
|
+
"-B"
|
23
|
+
else
|
24
|
+
Converter.to_bytes(@progress.total)
|
25
|
+
end
|
26
|
+
value.gsub(matcher, bytes)
|
31
27
|
end
|
32
28
|
end # TotalByteFormatter
|
33
29
|
end # ProgressBar
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
require_relative "pipeline"
|
6
|
+
|
7
|
+
require_relative "formatter/bar"
|
8
|
+
require_relative "formatter/current"
|
9
|
+
require_relative "formatter/current_byte"
|
10
|
+
require_relative "formatter/elapsed"
|
11
|
+
require_relative "formatter/estimated"
|
12
|
+
require_relative "formatter/estimated_time"
|
13
|
+
require_relative "formatter/percent"
|
14
|
+
require_relative "formatter/rate"
|
15
|
+
require_relative "formatter/byte_rate"
|
16
|
+
require_relative "formatter/mean_rate"
|
17
|
+
require_relative "formatter/mean_byte"
|
18
|
+
require_relative "formatter/total"
|
19
|
+
require_relative "formatter/total_byte"
|
20
|
+
|
21
|
+
module TTY
|
22
|
+
class ProgressBar
|
23
|
+
class Formatters
|
24
|
+
extend Forwardable
|
25
|
+
|
26
|
+
def_delegators :@pipeline, :decorate, :use
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def initialize(pipeline = nil)
|
30
|
+
@pipeline = pipeline || TTY::ProgressBar::Pipeline.new
|
31
|
+
end
|
32
|
+
|
33
|
+
# Prepare default pipeline formatters
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def load(progress)
|
37
|
+
@pipeline.use TTY::ProgressBar::CurrentFormatter.new(progress)
|
38
|
+
@pipeline.use TTY::ProgressBar::TotalFormatter.new(progress)
|
39
|
+
@pipeline.use TTY::ProgressBar::TotalByteFormatter.new(progress)
|
40
|
+
@pipeline.use TTY::ProgressBar::ElapsedFormatter.new(progress)
|
41
|
+
@pipeline.use TTY::ProgressBar::EstimatedTimeFormatter.new(progress)
|
42
|
+
@pipeline.use TTY::ProgressBar::EstimatedFormatter.new(progress)
|
43
|
+
@pipeline.use TTY::ProgressBar::PercentFormatter.new(progress)
|
44
|
+
@pipeline.use TTY::ProgressBar::ByteFormatter.new(progress)
|
45
|
+
@pipeline.use TTY::ProgressBar::ByteRateFormatter.new(progress)
|
46
|
+
@pipeline.use TTY::ProgressBar::RateFormatter.new(progress)
|
47
|
+
@pipeline.use TTY::ProgressBar::MeanRateFormatter.new(progress)
|
48
|
+
@pipeline.use TTY::ProgressBar::MeanByteFormatter.new(progress)
|
49
|
+
@pipeline.use TTY::ProgressBar::BarFormatter.new(progress)
|
50
|
+
end
|
51
|
+
end # Formatters
|
52
|
+
end # ProgressBar
|
53
|
+
end # TTY
|
@@ -5,7 +5,7 @@ module TTY
|
|
5
5
|
# Used by {ProgressBar} to measure progress rate per interval
|
6
6
|
# by default 1s
|
7
7
|
#
|
8
|
-
# @api
|
8
|
+
# @api private
|
9
9
|
class Meter
|
10
10
|
# Create Meter
|
11
11
|
#
|
@@ -103,7 +103,7 @@ module TTY
|
|
103
103
|
last_value / (last_at - @start_time)
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
alias avg_rate mean_rate
|
107
107
|
|
108
108
|
# Reset the meter by clearing out it's metrics
|
109
109
|
#
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "forwardable"
|
4
|
+
require "monitor"
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "../progressbar"
|
7
7
|
|
8
8
|
module TTY
|
9
9
|
class ProgressBar
|
@@ -21,9 +21,9 @@ module TTY
|
|
21
21
|
def_delegators :@top_bar, :width, :width=
|
22
22
|
|
23
23
|
DEFAULT_INSET = {
|
24
|
-
top: Gem.win_platform? ?
|
25
|
-
middle: Gem.win_platform? ?
|
26
|
-
bottom: Gem.win_platform? ?
|
24
|
+
top: Gem.win_platform? ? "+ " : "\u250c ",
|
25
|
+
middle: Gem.win_platform? ? "|-- " : "\u251c\u2500\u2500 ",
|
26
|
+
bottom: Gem.win_platform? ? "|__ " : "\u2514\u2500\u2500 "
|
27
27
|
}.freeze
|
28
28
|
|
29
29
|
# Number of currently occupied rows in terminal display
|
@@ -54,12 +54,13 @@ module TTY
|
|
54
54
|
@top_bar = register(format, observable: false) if format
|
55
55
|
|
56
56
|
@width = @options[:width]
|
57
|
-
@top_bar.update(width: @width) if @width
|
57
|
+
@top_bar.update(width: @width) if @top_bar && @width
|
58
58
|
|
59
59
|
@callbacks = {
|
60
60
|
progress: [],
|
61
|
-
stopped:
|
62
|
-
|
61
|
+
stopped: [],
|
62
|
+
paused: [],
|
63
|
+
done: []
|
63
64
|
}
|
64
65
|
end
|
65
66
|
|
@@ -79,6 +80,7 @@ module TTY
|
|
79
80
|
observe(bar) if observable
|
80
81
|
if @top_bar
|
81
82
|
@top_bar.update(total: total)
|
83
|
+
@top_bar.resume if @top_bar.done?
|
82
84
|
@top_bar.update(width: total) unless @width
|
83
85
|
end
|
84
86
|
end
|
@@ -104,14 +106,15 @@ module TTY
|
|
104
106
|
def observe(bar)
|
105
107
|
bar.on(:progress, &progress_handler)
|
106
108
|
.on(:done) { emit(:done) if complete? }
|
107
|
-
.on(:stopped)
|
109
|
+
.on(:stopped) { emit(:stopped) if stopped? }
|
110
|
+
.on(:paused) { emit(:paused) if paused? }
|
108
111
|
end
|
109
112
|
|
110
113
|
# Handle the progress event
|
111
114
|
#
|
112
115
|
# @api private
|
113
116
|
def progress_handler
|
114
|
-
->
|
117
|
+
->(progress) do
|
115
118
|
@top_bar.advance(progress) if @top_bar
|
116
119
|
emit(:progress, progress)
|
117
120
|
end
|
@@ -139,7 +142,7 @@ module TTY
|
|
139
142
|
# @api public
|
140
143
|
def total
|
141
144
|
synchronize do
|
142
|
-
(@bars - [@top_bar]).
|
145
|
+
(@bars - [@top_bar]).map(&:total).reduce(&:+)
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
@@ -150,7 +153,7 @@ module TTY
|
|
150
153
|
# @api public
|
151
154
|
def current
|
152
155
|
synchronize do
|
153
|
-
(@bars - [@top_bar]).
|
156
|
+
(@bars - [@top_bar]).map(&:current).reduce(&:+)
|
154
157
|
end
|
155
158
|
end
|
156
159
|
|
@@ -161,18 +164,40 @@ module TTY
|
|
161
164
|
# @api public
|
162
165
|
def complete?
|
163
166
|
synchronize do
|
164
|
-
(@bars - [@top_bar]).
|
167
|
+
(@bars - [@top_bar]).all?(&:complete?)
|
165
168
|
end
|
166
169
|
end
|
167
170
|
|
168
|
-
# Check if
|
171
|
+
# Check if all of the registered progress bars is stopped
|
169
172
|
#
|
170
173
|
# @return [Boolean]
|
171
174
|
#
|
172
175
|
# @api public
|
173
176
|
def stopped?
|
174
177
|
synchronize do
|
175
|
-
(@bars - [@top_bar]).
|
178
|
+
(@bars - [@top_bar]).all?(&:stopped?)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Check if all bars are stopped or finished
|
183
|
+
#
|
184
|
+
# @return [Boolean]
|
185
|
+
#
|
186
|
+
# @api public
|
187
|
+
def done?
|
188
|
+
synchronize do
|
189
|
+
(@bars - [@top_bar]).all?(&:done?)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Check if all bars are paused
|
194
|
+
#
|
195
|
+
# @return [Boolean]
|
196
|
+
#
|
197
|
+
# @api public
|
198
|
+
def paused?
|
199
|
+
synchronize do
|
200
|
+
(@bars - [@top_bar]).all?(&:paused?)
|
176
201
|
end
|
177
202
|
end
|
178
203
|
|
@@ -180,14 +205,28 @@ module TTY
|
|
180
205
|
#
|
181
206
|
# @api public
|
182
207
|
def stop
|
183
|
-
@bars.
|
208
|
+
@bars.each(&:stop)
|
184
209
|
end
|
185
210
|
|
186
211
|
# Finish all progress bars
|
187
212
|
#
|
188
213
|
# @api public
|
189
214
|
def finish
|
190
|
-
@bars.
|
215
|
+
@bars.each(&:finish)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Pause all progress bars
|
219
|
+
#
|
220
|
+
# @api public
|
221
|
+
def pause
|
222
|
+
@bars.each(&:pause)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Resume all progress bars
|
226
|
+
#
|
227
|
+
# @api public
|
228
|
+
def resume
|
229
|
+
@bars.each(&:resume)
|
191
230
|
end
|
192
231
|
|
193
232
|
# Find the number of characters to move into the line
|
@@ -201,7 +240,7 @@ module TTY
|
|
201
240
|
#
|
202
241
|
# @api public
|
203
242
|
def line_inset(bar)
|
204
|
-
return
|
243
|
+
return "" if @top_bar.nil?
|
205
244
|
|
206
245
|
case bar.row
|
207
246
|
when @top_bar.row
|
@@ -221,8 +260,9 @@ module TTY
|
|
221
260
|
# @api public
|
222
261
|
def on(name, &callback)
|
223
262
|
unless @callbacks.key?(name)
|
224
|
-
raise ArgumentError, "The event #{name} does not exist. "\
|
225
|
-
"
|
263
|
+
raise ArgumentError, "The event #{name} does not exist. " \
|
264
|
+
"Use :progress, :stopped, :paused or " \
|
265
|
+
":done instead"
|
226
266
|
end
|
227
267
|
@callbacks[name] << callback
|
228
268
|
self
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TTY
|
2
4
|
class ProgressBar
|
3
5
|
# Used by {ProgressBar} to decorate format string
|
@@ -17,24 +19,29 @@ module TTY
|
|
17
19
|
# Add a new formatter
|
18
20
|
#
|
19
21
|
# @example
|
20
|
-
# use(TTY::ProgressBar::TotalFormatter)
|
22
|
+
# use(TTY::ProgressBar::TotalFormatter.new(progress_bar))
|
21
23
|
#
|
22
24
|
# @api public
|
23
25
|
def use(formatter)
|
24
|
-
formatters <<
|
26
|
+
formatters << formatter
|
25
27
|
end
|
26
28
|
|
27
29
|
# Decorate the tokenized string with actual values
|
28
30
|
#
|
31
|
+
# @example
|
32
|
+
# decorate("[:bar] :current :elapsed")
|
33
|
+
#
|
34
|
+
# @param [String] tokenized
|
35
|
+
# the string with tokens
|
36
|
+
#
|
29
37
|
# @return [nil]
|
30
38
|
#
|
31
39
|
# @api private
|
32
|
-
def decorate(
|
40
|
+
def decorate(tokenized)
|
33
41
|
base = tokenized.dup
|
34
42
|
formatters.inject(base) do |formatted, formatter|
|
35
|
-
|
36
|
-
|
37
|
-
instance.format(formatted)
|
43
|
+
if formatter.respond_to?(:matches?) && formatter.matches?(formatted)
|
44
|
+
formatter.(formatted)
|
38
45
|
else
|
39
46
|
formatted
|
40
47
|
end
|