tty-progressbar 0.14.0 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +98 -21
- data/LICENSE.txt +1 -1
- data/README.md +511 -119
- data/lib/tty-progressbar.rb +2 -2
- data/lib/tty/progressbar.rb +216 -87
- data/lib/tty/progressbar/configuration.rb +124 -16
- 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 +87 -29
- 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 +69 -23
- data/lib/tty/progressbar/pipeline.rb +13 -6
- data/lib/tty/progressbar/timer.rb +89 -0
- data/lib/tty/progressbar/version.rb +3 -1
- metadata +65 -151
- data/.codeclimate.yml +0 -11
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.travis.yml +0 -25
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -14
- data/Rakefile +0 -8
- data/appveyor.yml +0 -21
- 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/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/spec/spec_helper.rb +0 -50
- 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 -16
- 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/stop_spec.rb +0 -15
- data/spec/unit/new_spec.rb +0 -66
- data/spec/unit/pipeline_spec.rb +0 -19
- data/spec/unit/ratio_spec.rb +0 -31
- 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 -21
- data/tasks/console.rake +0 -9
- data/tasks/coverage.rake +0 -9
- data/tasks/spec.rake +0 -27
- data/tty-progressbar.gemspec +0 -30
@@ -1,27 +1,14 @@
|
|
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 bar
|
6
8
|
#
|
7
9
|
# @api private
|
8
10
|
class BarFormatter
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(progress)
|
12
|
-
@progress = progress
|
13
|
-
end
|
14
|
-
|
15
|
-
# Determines whether this formatter is applied or not.
|
16
|
-
#
|
17
|
-
# @param [Object] value
|
18
|
-
#
|
19
|
-
# @return [Boolean]
|
20
|
-
#
|
21
|
-
# @api private
|
22
|
-
def matches?(value)
|
23
|
-
!!(value.to_s =~ MATCHER)
|
24
|
-
end
|
11
|
+
include TTY::ProgressBar::Formatter[/:bar/i.freeze]
|
25
12
|
|
26
13
|
# Format :bar token
|
27
14
|
#
|
@@ -29,19 +16,90 @@ module TTY
|
|
29
16
|
# the value being formatted
|
30
17
|
#
|
31
18
|
# @api public
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
19
|
+
def call(value)
|
20
|
+
without_bar = value.gsub(/:bar/, "")
|
21
|
+
available_space = [0, ProgressBar.max_columns -
|
22
|
+
ProgressBar.display_columns(without_bar) -
|
23
|
+
@progress.inset].max
|
24
|
+
width = [@progress.width.to_i, available_space].min
|
25
|
+
|
26
|
+
# When we don't know the total progress, use either user
|
27
|
+
# defined width or rely on terminal width detection
|
28
|
+
if @progress.indeterminate?
|
29
|
+
width = available_space if width.zero?
|
30
|
+
|
31
|
+
format_indeterminate(value, width)
|
32
|
+
else
|
33
|
+
format_determinate(value, width)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def format_indeterminate(value, width)
|
41
|
+
buffer = []
|
42
|
+
possible_width = width
|
43
|
+
unknown_char_length = ProgressBar.display_columns(@progress.unknown)
|
44
|
+
complete_char_length = ProgressBar.display_columns(@progress.complete)
|
45
|
+
incomplete_char_length = ProgressBar.display_columns(@progress.incomplete)
|
46
|
+
head_char_length = ProgressBar.display_columns(@progress.head)
|
47
|
+
|
48
|
+
possible_width -= unknown_char_length
|
49
|
+
max_char_length = [complete_char_length, incomplete_char_length,
|
50
|
+
head_char_length].max
|
51
|
+
# figure out how many unicode chars would fit normally
|
52
|
+
# when the bar has total to prevent resizing
|
53
|
+
possible_width = (possible_width / max_char_length) * max_char_length
|
54
|
+
complete = (possible_width * @progress.ratio).round
|
55
|
+
incomplete = possible_width - complete
|
56
|
+
|
57
|
+
buffer << " " * complete
|
58
|
+
buffer << @progress.unknown
|
59
|
+
buffer << " " * incomplete
|
60
|
+
|
61
|
+
value.gsub(matcher, buffer.join)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def format_determinate(value, width)
|
66
|
+
complete_bar_length = (width * @progress.ratio).round
|
67
|
+
complete_char_length = ProgressBar.display_columns(@progress.complete)
|
68
|
+
incomplete_char_length = ProgressBar.display_columns(@progress.incomplete)
|
69
|
+
head_char_length = ProgressBar.display_columns(@progress.head)
|
70
|
+
|
71
|
+
# division by char length only when unicode chars are used
|
72
|
+
# otherwise it has no effect on regular ascii chars
|
73
|
+
complete_items = [
|
74
|
+
complete_bar_length / complete_char_length,
|
75
|
+
# or see how many incomplete (unicode) items fit
|
76
|
+
(complete_bar_length / incomplete_char_length) * incomplete_char_length
|
77
|
+
].min
|
78
|
+
|
79
|
+
complete_width = complete_items * complete_char_length
|
80
|
+
incomplete_width = width - complete_width
|
81
|
+
incomplete_items = [
|
82
|
+
incomplete_width / incomplete_char_length,
|
83
|
+
# or see how many complete (unicode) items fit
|
84
|
+
(incomplete_width / complete_char_length) * complete_char_length
|
85
|
+
].min
|
86
|
+
|
87
|
+
complete = Array.new(complete_items, @progress.complete)
|
88
|
+
incomplete = Array.new(incomplete_items, @progress.incomplete)
|
89
|
+
|
90
|
+
if complete_items > 0 && head_char_length > 0 &&
|
91
|
+
(incomplete_items > 0 || incomplete_items.zero? && !@progress.clear_head)
|
92
|
+
# see how many head chars per complete char
|
93
|
+
times = (head_char_length / complete_char_length.to_f).round
|
94
|
+
if complete_items < times # not enough complete chars to fit
|
95
|
+
incomplete.pop(times - complete_items)
|
96
|
+
end
|
97
|
+
complete.pop(times)
|
98
|
+
extra_space = " " * (times * complete_char_length - head_char_length)
|
99
|
+
complete << "#{@progress.head}#{extra_space}"
|
100
|
+
end
|
101
|
+
|
102
|
+
value.gsub(matcher, "#{complete.join}#{incomplete.join}")
|
45
103
|
end
|
46
104
|
end # BarFormatter
|
47
105
|
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,32 +9,17 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class ByteRateFormatter
|
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[/:byte_rate/i.freeze]
|
27
13
|
|
28
14
|
# Format :byte_rate token
|
29
15
|
#
|
30
16
|
# @param [String] value
|
31
|
-
# the value
|
17
|
+
# the value to format
|
32
18
|
#
|
33
19
|
# @api public
|
34
|
-
def
|
20
|
+
def call(value)
|
35
21
|
formatted = Converter.to_bytes(@progress.rate)
|
36
|
-
value.gsub(
|
22
|
+
value.gsub(matcher, formatted)
|
37
23
|
end
|
38
24
|
end # ByteRateFormatter
|
39
25
|
end # ProgressBar
|
@@ -6,31 +6,16 @@ module TTY
|
|
6
6
|
#
|
7
7
|
# @api private
|
8
8
|
class CurrentFormatter
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(progress)
|
12
|
-
@progress = progress
|
13
|
-
end
|
14
|
-
|
15
|
-
# Determines whether this formatter is applied or not.
|
16
|
-
#
|
17
|
-
# @param [Object] value
|
18
|
-
#
|
19
|
-
# @return [Boolean]
|
20
|
-
#
|
21
|
-
# @api private
|
22
|
-
def matches?(value)
|
23
|
-
!!(value.to_s =~ MATCHER)
|
24
|
-
end
|
9
|
+
include TTY::ProgressBar::Formatter[/:current\b/i.freeze]
|
25
10
|
|
26
11
|
# Format :current token
|
27
12
|
#
|
28
13
|
# @param [String] value
|
29
|
-
# the value
|
14
|
+
# the value to format
|
30
15
|
#
|
31
16
|
# @api public
|
32
|
-
def
|
33
|
-
value.gsub(
|
17
|
+
def call(value)
|
18
|
+
value.gsub(matcher, @progress.current.to_s)
|
34
19
|
end
|
35
20
|
end # CurrentFormatter
|
36
21
|
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,17 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class ByteFormatter
|
11
|
-
|
12
|
+
include TTY::ProgressBar::Formatter[/(:current_byte|:byte)\b/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 :current_byte token
|
20
15
|
#
|
21
|
-
# @
|
16
|
+
# @param [String] value
|
17
|
+
# the value to format
|
22
18
|
#
|
23
|
-
# @api
|
24
|
-
def
|
25
|
-
!!(value.to_s =~ MATCHER)
|
26
|
-
end
|
27
|
-
|
28
|
-
def format(value)
|
19
|
+
# @api public
|
20
|
+
def call(value)
|
29
21
|
bytes = Converter.to_bytes(@progress.current)
|
30
|
-
value.gsub(
|
22
|
+
value.gsub(matcher, bytes)
|
31
23
|
end
|
32
24
|
end # ByteFormatter
|
33
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,26 +9,16 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class ElapsedFormatter
|
11
|
-
|
12
|
+
include TTY::ProgressBar::Formatter[/:elapsed/.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 :elapsed token
|
20
15
|
#
|
21
|
-
# @
|
16
|
+
# @param [String] value
|
17
|
+
# the value to format
|
22
18
|
#
|
23
|
-
# @api
|
24
|
-
def
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def format(value)
|
29
|
-
elapsed = (Time.now - @progress.start_at)
|
30
|
-
value.gsub(MATCHER, Converter.to_time(elapsed))
|
19
|
+
# @api public
|
20
|
+
def call(value)
|
21
|
+
value.gsub(matcher, Converter.to_time(@progress.elapsed_time))
|
31
22
|
end
|
32
23
|
end # ElapsedFormatter
|
33
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,29 +9,24 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class EstimatedFormatter
|
11
|
-
|
12
|
+
include TTY::ProgressBar::Formatter[/:eta/.freeze]
|
12
13
|
|
13
|
-
|
14
|
-
@progress = progress
|
15
|
-
end
|
16
|
-
|
17
|
-
# Determines whether this formatter is applied or not.
|
14
|
+
# Format :eta token
|
18
15
|
#
|
19
|
-
# @param [
|
16
|
+
# @param [String] value
|
17
|
+
# the value to format
|
20
18
|
#
|
21
|
-
# @
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
19
|
+
# @api public
|
20
|
+
def call(value)
|
21
|
+
if @progress.indeterminate?
|
22
|
+
return value.gsub(matcher, "--s")
|
23
|
+
end
|
27
24
|
|
28
|
-
|
29
|
-
elapsed = Time.now - @progress.start_at
|
25
|
+
elapsed = @progress.elapsed_time
|
30
26
|
estimated = (elapsed / @progress.ratio).to_f - elapsed
|
31
27
|
estimated = (estimated.infinite? || estimated < 0) ? 0.0 : estimated
|
32
|
-
value.gsub(
|
28
|
+
value.gsub(matcher, Converter.to_time(estimated))
|
33
29
|
end
|
34
|
-
end #
|
30
|
+
end # EstimatedFormatter
|
35
31
|
end # ProgressBar
|
36
32
|
end # TTY
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class ProgressBar
|
5
|
+
# Used by {Pipeline} to format :eta_time token
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class EstimatedTimeFormatter
|
9
|
+
include TTY::ProgressBar::Formatter[/:eta_time/.freeze]
|
10
|
+
|
11
|
+
# Format :eta_time token
|
12
|
+
#
|
13
|
+
# @param [String] value
|
14
|
+
# the value to format
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
def call(value)
|
18
|
+
if @progress.indeterminate?
|
19
|
+
return value.gsub(matcher, "--:--:--")
|
20
|
+
end
|
21
|
+
|
22
|
+
elapsed = @progress.elapsed_time
|
23
|
+
estimated = (elapsed / @progress.ratio).to_f - elapsed
|
24
|
+
estimated = (estimated.infinite? || estimated < 0) ? 0.0 : estimated
|
25
|
+
|
26
|
+
time_format = if estimated >= 86_400 # longer than a day
|
27
|
+
"%Y-%m-%d %H:%M:%S"
|
28
|
+
else
|
29
|
+
"%H:%M:%S"
|
30
|
+
end
|
31
|
+
completion_time = Time.now + estimated
|
32
|
+
eta_time = completion_time.strftime(time_format)
|
33
|
+
value.gsub(matcher, eta_time)
|
34
|
+
end
|
35
|
+
end # EstimatedTimeFormatter
|
36
|
+
end # ProgressBar
|
37
|
+
end # TTY
|
@@ -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,32 +9,17 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class MeanByteFormatter
|
11
|
-
|
12
|
+
include TTY::ProgressBar::Formatter[/:mean_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
|
20
|
-
#
|
21
|
-
# @return [Boolean]
|
22
|
-
#
|
23
|
-
# @api private
|
24
|
-
def matches?(value)
|
25
|
-
!!(value.to_s =~ MATCHER)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Format :rate token
|
14
|
+
# Format :mean_byte token
|
29
15
|
#
|
30
16
|
# @param [String] value
|
31
17
|
# the value being formatted
|
32
18
|
#
|
33
19
|
# @api public
|
34
|
-
def
|
20
|
+
def call(value)
|
35
21
|
formatted = Converter.to_bytes(@progress.mean_rate)
|
36
|
-
value.gsub(
|
22
|
+
value.gsub(matcher, formatted)
|
37
23
|
end
|
38
24
|
end # MeanByteFormatter
|
39
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,32 +9,17 @@ module TTY
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class MeanRateFormatter
|
11
|
-
|
12
|
+
include TTY::ProgressBar::Formatter[/:mean_rate/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
|
20
|
-
#
|
21
|
-
# @return [Boolean]
|
22
|
-
#
|
23
|
-
# @api private
|
24
|
-
def matches?(value)
|
25
|
-
!!(value.to_s =~ MATCHER)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Format :rate token
|
14
|
+
# Format :mean_rate token
|
29
15
|
#
|
30
16
|
# @param [String] value
|
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.mean_rate)
|
36
|
-
value.gsub(
|
22
|
+
value.gsub(matcher, formatted)
|
37
23
|
end
|
38
24
|
end # MeanRateFormatter
|
39
25
|
end # ProgressBar
|