kxi 1.0.1 → 1.0.2
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/kxi.rb +44 -39
- data/lib/kxi/application/config.rb +177 -177
- data/lib/kxi/application/config_reader.rb +16 -16
- data/lib/kxi/application/event.rb +35 -35
- data/lib/kxi/application/logger.rb +155 -155
- data/lib/kxi/application/version.rb +106 -74
- data/lib/kxi/application/version_expression.rb +94 -69
- data/lib/kxi/application/workspace.rb +105 -0
- data/lib/kxi/cli/anonymous_argument.rb +50 -50
- data/lib/kxi/cli/argument.rb +56 -56
- data/lib/kxi/cli/argument_values.rb +83 -83
- data/lib/kxi/cli/explicit_argument.rb +38 -38
- data/lib/kxi/cli/flag_argument.rb +15 -15
- data/lib/kxi/cli/named_argument.rb +59 -59
- data/lib/kxi/cli/property_list.rb +57 -48
- data/lib/kxi/cli/table.rb +82 -62
- data/lib/kxi/cli/verb.rb +282 -280
- data/lib/kxi/collections/array_collection.rb +106 -106
- data/lib/kxi/collections/enumerable.rb +527 -527
- data/lib/kxi/collections/enumerator.rb +31 -31
- data/lib/kxi/collections/hash_collection.rb +100 -100
- data/lib/kxi/collections/protected_collection.rb +20 -19
- data/lib/kxi/exceptions/abstract_exception.rb +34 -34
- data/lib/kxi/exceptions/argument_exception.rb +21 -21
- data/lib/kxi/exceptions/collection_exception.rb +13 -13
- data/lib/kxi/exceptions/configuration_exception.rb +36 -25
- data/lib/kxi/exceptions/dimension_mismatch_exception.rb +29 -0
- data/lib/kxi/exceptions/invalid_type_exception.rb +32 -32
- data/lib/kxi/exceptions/no_argument_exception.rb +20 -20
- data/lib/kxi/exceptions/not_implemented_exception.rb +12 -12
- data/lib/kxi/exceptions/out_of_range_exception.rb +43 -43
- data/lib/kxi/exceptions/parse_exception.rb +28 -20
- data/lib/kxi/exceptions/verb_expected_exception.rb +20 -20
- data/lib/kxi/exceptions/workspace_collision_exception.rb +21 -0
- data/lib/kxi/math/math.rb +45 -0
- data/lib/kxi/math/matrix.rb +303 -0
- data/lib/kxi/math/polynomial.rb +141 -101
- data/lib/kxi/math/vector.rb +181 -0
- data/lib/kxi/platform.rb +103 -57
- data/lib/kxi/reflection/stack_frame.rb +80 -80
- data/lib/kxi/version.rb +4 -4
- metadata +8 -3
- data/lib/kxi/exceptions/invalid_operation_exception.rb +0 -11
@@ -1,84 +1,84 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-21.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
# Manages values of arguments
|
6
|
-
class ArgumentValues
|
7
|
-
# Instantiates the {KXI::CLI::ArgumentValues} class
|
8
|
-
# @param args [Array<KXI::CLI::Argument>] Expected arguments
|
9
|
-
def initialize(args)
|
10
|
-
@args = args
|
11
|
-
@vals = {}
|
12
|
-
args.each do |a|
|
13
|
-
if a.is_a?(KXI::CLI::FlagArgument)
|
14
|
-
@vals[a.name] = { :argument => a, :value => false }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# Assigns (or adds) a value to argument
|
20
|
-
# @param arg [KXI::CLI::Argument] Argument to set
|
21
|
-
# @param val [String] Value to assign
|
22
|
-
def set(arg, val)
|
23
|
-
if arg.is_a?(KXI::CLI::FlagArgument)
|
24
|
-
raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Flag set multiple times!')) if @vals[arg.name][:value]
|
25
|
-
@vals[arg.name][:value] = val
|
26
|
-
else
|
27
|
-
if arg.variadic?
|
28
|
-
@vals[arg.name] = { :argument => arg, :value => [] } if @vals[arg.name] == nil
|
29
|
-
@vals[arg.name][:value].push(val)
|
30
|
-
else
|
31
|
-
raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Argument set multiple times!')) if @vals[arg.name] != nil
|
32
|
-
begin
|
33
|
-
arg.validate(val)
|
34
|
-
rescue Exception => ex
|
35
|
-
raise(KXI::Exceptions::ArgumentException.new(arg.name, ex.message))
|
36
|
-
end
|
37
|
-
@vals[arg.name] = { :argument => arg, :value => val }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Gets value of argument
|
43
|
-
# @param index [String, Symbol, KXI::CLI::Argument] Name of argument
|
44
|
-
# @return [String] Value of argument
|
45
|
-
def [](index)
|
46
|
-
if index.is_a?(Symbol)
|
47
|
-
index = index.to_s
|
48
|
-
elsif index.is_a?(KXI::CLI::Argument)
|
49
|
-
index = index.name
|
50
|
-
end
|
51
|
-
raise(Exception.new("Undefined argument '#{index}'!")) unless @vals.include?(index)
|
52
|
-
return @vals[index][:value]
|
53
|
-
end
|
54
|
-
|
55
|
-
# Converts class to
|
56
|
-
# @return [Hash] Equivalent hash
|
57
|
-
def to_h
|
58
|
-
ret = {}
|
59
|
-
@vals.each_pair do |k, v|
|
60
|
-
ret[k] = v[:value]
|
61
|
-
end
|
62
|
-
return ret
|
63
|
-
end
|
64
|
-
|
65
|
-
# Validates variadic arguments and checks for minimal argument requirements
|
66
|
-
def finish
|
67
|
-
@args.each do |arg|
|
68
|
-
if @vals.include?(arg.name)
|
69
|
-
unless arg.is_a?(KXI::CLI::FlagArgument)
|
70
|
-
begin
|
71
|
-
arg.validate(@vals[arg.name][:value])
|
72
|
-
rescue Exception => ex
|
73
|
-
raise(KXI::Exceptions::ArgumentException.new(arg.name, ex.message))
|
74
|
-
end
|
75
|
-
end
|
76
|
-
else
|
77
|
-
raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Argument is mandatory!')) if arg.required?
|
78
|
-
@vals[arg.name] = { :argument => arg, :value => arg.default }
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-21.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Manages values of arguments
|
6
|
+
class ArgumentValues
|
7
|
+
# Instantiates the {KXI::CLI::ArgumentValues} class
|
8
|
+
# @param args [Array<KXI::CLI::Argument>] Expected arguments
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
@vals = {}
|
12
|
+
args.each do |a|
|
13
|
+
if a.is_a?(KXI::CLI::FlagArgument)
|
14
|
+
@vals[a.name] = { :argument => a, :value => false }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Assigns (or adds) a value to argument
|
20
|
+
# @param arg [KXI::CLI::Argument] Argument to set
|
21
|
+
# @param val [String] Value to assign
|
22
|
+
def set(arg, val)
|
23
|
+
if arg.is_a?(KXI::CLI::FlagArgument)
|
24
|
+
raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Flag set multiple times!')) if @vals[arg.name][:value]
|
25
|
+
@vals[arg.name][:value] = val
|
26
|
+
else
|
27
|
+
if arg.variadic?
|
28
|
+
@vals[arg.name] = { :argument => arg, :value => [] } if @vals[arg.name] == nil
|
29
|
+
@vals[arg.name][:value].push(val)
|
30
|
+
else
|
31
|
+
raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Argument set multiple times!')) if @vals[arg.name] != nil
|
32
|
+
begin
|
33
|
+
arg.validate(val)
|
34
|
+
rescue Exception => ex
|
35
|
+
raise(KXI::Exceptions::ArgumentException.new(arg.name, ex.message))
|
36
|
+
end
|
37
|
+
@vals[arg.name] = { :argument => arg, :value => val }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Gets value of argument
|
43
|
+
# @param index [String, Symbol, KXI::CLI::Argument] Name of argument
|
44
|
+
# @return [String] Value of argument
|
45
|
+
def [](index)
|
46
|
+
if index.is_a?(Symbol)
|
47
|
+
index = index.to_s
|
48
|
+
elsif index.is_a?(KXI::CLI::Argument)
|
49
|
+
index = index.name
|
50
|
+
end
|
51
|
+
raise(Exception.new("Undefined argument '#{index}'!")) unless @vals.include?(index)
|
52
|
+
return @vals[index][:value]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Converts class to hash
|
56
|
+
# @return [Hash] Equivalent hash
|
57
|
+
def to_h
|
58
|
+
ret = {}
|
59
|
+
@vals.each_pair do |k, v|
|
60
|
+
ret[k] = v[:value]
|
61
|
+
end
|
62
|
+
return ret
|
63
|
+
end
|
64
|
+
|
65
|
+
# Validates variadic arguments and checks for minimal argument requirements
|
66
|
+
def finish
|
67
|
+
@args.each do |arg|
|
68
|
+
if @vals.include?(arg.name)
|
69
|
+
unless arg.is_a?(KXI::CLI::FlagArgument)
|
70
|
+
begin
|
71
|
+
arg.validate(@vals[arg.name][:value])
|
72
|
+
rescue Exception => ex
|
73
|
+
raise(KXI::Exceptions::ArgumentException.new(arg.name, ex.message))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
else
|
77
|
+
raise(KXI::Exceptions::ArgumentException.new(arg.name, 'Argument is mandatory!')) if arg.required?
|
78
|
+
@vals[arg.name] = { :argument => arg, :value => arg.default }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
84
|
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
# Represents argument specified explicitly with name
|
6
|
-
class ExplicitArgument < KXI::CLI::Argument
|
7
|
-
# Gets full descriptive name of argument
|
8
|
-
# @return [String] Full name of argument
|
9
|
-
def headline
|
10
|
-
ret = ''
|
11
|
-
ret = "-#{@sh}, " if @sh != nil
|
12
|
-
ret += "--#{name}"
|
13
|
-
return ret
|
14
|
-
end
|
15
|
-
|
16
|
-
# Gets syntax of argument
|
17
|
-
# @return [String] Syntax of argument
|
18
|
-
def syntax
|
19
|
-
headline
|
20
|
-
end
|
21
|
-
|
22
|
-
# Gets the shortcut symbol of argument
|
23
|
-
# @return [String] Shortcut symbol of argument
|
24
|
-
def shortcut
|
25
|
-
@sh
|
26
|
-
end
|
27
|
-
|
28
|
-
# Instantiates the {KXI::CLI::ExplicitArgument} class
|
29
|
-
# @param nm [String] Name of argument
|
30
|
-
# @param desc [String] Description of argument
|
31
|
-
# @param sh [String, nil] Shortcut of argument
|
32
|
-
# @param req [Bool] Specifies whether argument is mandatory
|
33
|
-
def initialize(nm, desc, sh = nil, req = false)
|
34
|
-
super(nm, desc, req, req ? 2 : 1)
|
35
|
-
@sh = sh
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Represents argument specified explicitly with name
|
6
|
+
class ExplicitArgument < KXI::CLI::Argument
|
7
|
+
# Gets full descriptive name of argument
|
8
|
+
# @return [String] Full name of argument
|
9
|
+
def headline
|
10
|
+
ret = ''
|
11
|
+
ret = "-#{@sh}, " if @sh != nil
|
12
|
+
ret += "--#{name}"
|
13
|
+
return ret
|
14
|
+
end
|
15
|
+
|
16
|
+
# Gets syntax of argument
|
17
|
+
# @return [String] Syntax of argument
|
18
|
+
def syntax
|
19
|
+
headline
|
20
|
+
end
|
21
|
+
|
22
|
+
# Gets the shortcut symbol of argument
|
23
|
+
# @return [String] Shortcut symbol of argument
|
24
|
+
def shortcut
|
25
|
+
@sh
|
26
|
+
end
|
27
|
+
|
28
|
+
# Instantiates the {KXI::CLI::ExplicitArgument} class
|
29
|
+
# @param nm [String] Name of argument
|
30
|
+
# @param desc [String] Description of argument
|
31
|
+
# @param sh [String, nil] Shortcut of argument
|
32
|
+
# @param req [Bool] Specifies whether argument is mandatory
|
33
|
+
def initialize(nm, desc, sh = nil, req = false)
|
34
|
+
super(nm, desc, req, req ? 2 : 1)
|
35
|
+
@sh = sh
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
39
|
end
|
@@ -1,16 +1,16 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
# Represents the flag argument (eg.: -f, --flag)
|
6
|
-
class FlagArgument < KXI::CLI::ExplicitArgument
|
7
|
-
# Instantiates the {KXI::CLI::FlagArgument} class
|
8
|
-
# @param nm [String] Name of argument
|
9
|
-
# @param desc [String] Description of argument
|
10
|
-
# @param sh [String] Shortcut of argument
|
11
|
-
def initialize(nm, desc, sh = nil)
|
12
|
-
super(nm, desc, sh)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Represents the flag argument (eg.: -f, --flag)
|
6
|
+
class FlagArgument < KXI::CLI::ExplicitArgument
|
7
|
+
# Instantiates the {KXI::CLI::FlagArgument} class
|
8
|
+
# @param nm [String] Name of argument
|
9
|
+
# @param desc [String] Description of argument
|
10
|
+
# @param sh [String] Shortcut of argument
|
11
|
+
def initialize(nm, desc, sh = nil)
|
12
|
+
super(nm, desc, sh)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
16
|
end
|
@@ -1,60 +1,60 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
# Represents named argument (eg.: -a VALUE, --argument VALUE)
|
6
|
-
class NamedArgument < KXI::CLI::ExplicitArgument
|
7
|
-
# Gets default value of argument
|
8
|
-
# @return [Object] Default value of argument
|
9
|
-
def default
|
10
|
-
@def
|
11
|
-
end
|
12
|
-
|
13
|
-
# Gets whether argument is variadic
|
14
|
-
# @return [Bool] True if argument is variadic; false otherwise
|
15
|
-
def variadic?
|
16
|
-
@var
|
17
|
-
end
|
18
|
-
|
19
|
-
# Gets name of argument value
|
20
|
-
# @return [String] Name of argument value
|
21
|
-
def value_name
|
22
|
-
@vnm
|
23
|
-
end
|
24
|
-
|
25
|
-
# Gets full descriptive name of argument
|
26
|
-
# @return [String] Full name of argument
|
27
|
-
def headline
|
28
|
-
"#{super} #{@var ? '...' : ''}#{@vnm.upcase}"
|
29
|
-
end
|
30
|
-
|
31
|
-
# Gets syntax of argument
|
32
|
-
# @return [String] Syntax of argument
|
33
|
-
def syntax
|
34
|
-
"-#{(shortcut != nil ? shortcut : "-#{name}")} #{required? ? '<' : '['}#{@var ? '...' : ''}#{@vnm}#{required? ? '>' : ']'}"
|
35
|
-
end
|
36
|
-
|
37
|
-
# Instantiates the {KXI::CLI::NamedArgument} class
|
38
|
-
# @param nm [String] Name of argument
|
39
|
-
# @param vn [String] Name of value
|
40
|
-
# @param desc [String] Description of argument
|
41
|
-
# @param sh [String] Shortcut of argument
|
42
|
-
# @param rq [Bool] Indicates whether argument is required
|
43
|
-
# @param df Default value of argument
|
44
|
-
# @param var [Bool] Indicates whether argument is variadic
|
45
|
-
def initialize(nm, vn, desc, sh = nil, rq = true, df = nil, var = false, &validator)
|
46
|
-
super(nm, desc, sh, rq)
|
47
|
-
@def = df
|
48
|
-
@vnm = vn
|
49
|
-
@var = var
|
50
|
-
@val = validator
|
51
|
-
end
|
52
|
-
|
53
|
-
# Validates value of argument
|
54
|
-
# @param val [String, Array<String>] Value of argument
|
55
|
-
def validate(val)
|
56
|
-
@val.call(val) if @val != nil
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-20.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Represents named argument (eg.: -a VALUE, --argument VALUE)
|
6
|
+
class NamedArgument < KXI::CLI::ExplicitArgument
|
7
|
+
# Gets default value of argument
|
8
|
+
# @return [Object] Default value of argument
|
9
|
+
def default
|
10
|
+
@def
|
11
|
+
end
|
12
|
+
|
13
|
+
# Gets whether argument is variadic
|
14
|
+
# @return [Bool] True if argument is variadic; false otherwise
|
15
|
+
def variadic?
|
16
|
+
@var
|
17
|
+
end
|
18
|
+
|
19
|
+
# Gets name of argument value
|
20
|
+
# @return [String] Name of argument value
|
21
|
+
def value_name
|
22
|
+
@vnm
|
23
|
+
end
|
24
|
+
|
25
|
+
# Gets full descriptive name of argument
|
26
|
+
# @return [String] Full name of argument
|
27
|
+
def headline
|
28
|
+
"#{super} #{@var ? '...' : ''}#{@vnm.upcase}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Gets syntax of argument
|
32
|
+
# @return [String] Syntax of argument
|
33
|
+
def syntax
|
34
|
+
"-#{(shortcut != nil ? shortcut : "-#{name}")} #{required? ? '<' : '['}#{@var ? '...' : ''}#{@vnm}#{required? ? '>' : ']'}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Instantiates the {KXI::CLI::NamedArgument} class
|
38
|
+
# @param nm [String] Name of argument
|
39
|
+
# @param vn [String] Name of value
|
40
|
+
# @param desc [String] Description of argument
|
41
|
+
# @param sh [String] Shortcut of argument
|
42
|
+
# @param rq [Bool] Indicates whether argument is required
|
43
|
+
# @param df Default value of argument
|
44
|
+
# @param var [Bool] Indicates whether argument is variadic
|
45
|
+
def initialize(nm, vn, desc, sh = nil, rq = true, df = nil, var = false, &validator)
|
46
|
+
super(nm, desc, sh, rq)
|
47
|
+
@def = df
|
48
|
+
@vnm = vn
|
49
|
+
@var = var
|
50
|
+
@val = validator
|
51
|
+
end
|
52
|
+
|
53
|
+
# Validates value of argument
|
54
|
+
# @param val [String, Array<String>] Value of argument
|
55
|
+
def validate(val)
|
56
|
+
@val.call(val) if @val != nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
60
|
end
|
@@ -1,49 +1,58 @@
|
|
1
|
-
# Created by Matyáš Pokorný on 2018-01-24.
|
2
|
-
|
3
|
-
module KXI
|
4
|
-
module CLI
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def
|
17
|
-
@data
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
1
|
+
# Created by Matyáš Pokorný on 2018-01-24.
|
2
|
+
|
3
|
+
module KXI
|
4
|
+
module CLI
|
5
|
+
# Property list renderer
|
6
|
+
class PropertyList
|
7
|
+
# Instantiates the {KXI::CLI::PropertyList} class
|
8
|
+
def initialize
|
9
|
+
@align = 0
|
10
|
+
@data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sets a property
|
14
|
+
# @param [string] name Name of the property
|
15
|
+
# @param [string,Array<string>] value Value of the property
|
16
|
+
def field(name, value)
|
17
|
+
@data[name] = value
|
18
|
+
@align = name.length if name.length > @align
|
19
|
+
end
|
20
|
+
|
21
|
+
# Renders the property list into stdout
|
22
|
+
# @param [integer] cols Determines the maximal number of columns for array rendering
|
23
|
+
def render(cols = 4)
|
24
|
+
@data.each_pair do |k, v|
|
25
|
+
if v.kind_of?(Array)
|
26
|
+
print("#{pad(k)}: ")
|
27
|
+
v.each_index do |idx|
|
28
|
+
if idx > 0 and idx % cols == 0
|
29
|
+
puts('')
|
30
|
+
print(' ' * (@align + 2))
|
31
|
+
elsif idx > 0
|
32
|
+
print(', ')
|
33
|
+
end
|
34
|
+
print(v[idx])
|
35
|
+
end
|
36
|
+
puts('')
|
37
|
+
else
|
38
|
+
puts("#{pad(k)}: #{v}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds a space-dot-space padding
|
44
|
+
# @param [string] key Key to add padding to
|
45
|
+
def pad(key)
|
46
|
+
d = false
|
47
|
+
p = ''
|
48
|
+
(@align - key.length).times do |i|
|
49
|
+
p = (d ? '.' : ' ') + p
|
50
|
+
d = (not d)
|
51
|
+
end
|
52
|
+
return key + p
|
53
|
+
end
|
54
|
+
|
55
|
+
private :pad
|
56
|
+
end
|
57
|
+
end
|
49
58
|
end
|