aba 0.0.1 → 0.5.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 +5 -5
- data/.gitignore +1 -0
- data/.rspec +3 -1
- data/.travis.yml +6 -0
- data/README.md +109 -18
- data/aba.gemspec +7 -6
- data/lib/aba.rb +6 -114
- data/lib/aba/batch.rb +224 -0
- data/lib/aba/entry.rb +17 -0
- data/lib/aba/return.rb +72 -0
- data/lib/aba/transaction.rb +99 -35
- data/lib/aba/validations.rb +84 -14
- data/lib/aba/version.rb +1 -1
- data/spec/lib/aba/batch_spec.rb +101 -0
- data/spec/lib/aba/return_spec.rb +47 -0
- data/spec/{transaction_spec.rb → lib/aba/transaction_spec.rb} +6 -5
- data/spec/lib/aba/validations_spec.rb +215 -0
- data/spec/lib/aba_spec.rb +21 -0
- data/spec/spec_helper.rb +2 -0
- metadata +40 -17
- data/spec/aba_spec.rb +0 -40
- data/spec/validations_spec.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f7d2996812bbfd9d6386cef252e680024545ad59b01eec0d6645d8cf75dafe6a
|
4
|
+
data.tar.gz: 584aad9a1c2b922680da873f1a95922dfa4864c5e54ac979d6ed6f5eb01e3094
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4be17e99ad4fedbb404bb2305e0a310afafc96c0f2b39f57f49d76b198e7018a7fc9997b35441d2209bce37986487d683fcfd5f20d049acea8581804669ecc8b
|
7
|
+
data.tar.gz: b09e75f48ce6ddab89dc0fc82f1d9be3a87f573db08591d65158203b2b1a4d1ae6c3ec6cbf34437d1c4d15842e4e93f07f75977bbf5ac063338fbd2dc519a177
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,34 +1,125 @@
|
|
1
|
+
[](https://travis-ci.org/andrba/aba) [](https://codeclimate.com/github/andrba/aba)
|
2
|
+
|
1
3
|
# Aba
|
2
4
|
|
3
|
-
|
5
|
+
Generates ABA (Australian Banking Association) file format output
|
4
6
|
|
5
7
|
## Usage
|
6
8
|
|
7
9
|
```ruby
|
8
10
|
require 'aba'
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
# Initialise ABA
|
13
|
+
aba = Aba.batch(
|
14
|
+
bsb: "123-345", # Optional (Not required by NAB)
|
15
|
+
financial_institution: "WPC",
|
16
|
+
user_name: "John Doe",
|
17
|
+
user_id: "466364",
|
18
|
+
description: "Payroll",
|
19
|
+
process_at: Time.now.strftime("%d%m%y")
|
20
|
+
)
|
21
|
+
|
22
|
+
# Add transactions...
|
23
|
+
10.times do
|
24
|
+
aba.add_transaction(
|
25
|
+
{
|
26
|
+
bsb: "342-342",
|
27
|
+
account_number: "3244654",
|
28
|
+
amount: 10000, # Amount in cents
|
29
|
+
account_name: "John Doe",
|
30
|
+
transaction_code: 53,
|
31
|
+
lodgement_reference: "R435564",
|
32
|
+
trace_bsb: "453-543",
|
33
|
+
trace_account_number: "45656733",
|
34
|
+
name_of_remitter: "Remitter"
|
35
|
+
}
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
# ...or add returns
|
40
|
+
10.times do
|
41
|
+
aba.add_return(
|
42
|
+
{
|
43
|
+
bsb: '453-543',
|
44
|
+
account_number: '45656733',
|
45
|
+
amount: 10000,
|
46
|
+
account_name: 'John Doe',
|
47
|
+
transaction_code: 53,
|
48
|
+
lodgement_reference: 'R435564',
|
49
|
+
trace_bsb: '342-342',
|
50
|
+
trace_account_number: '3244654',
|
51
|
+
name_of_remitter: 'Remitter',
|
52
|
+
return_code: 8,
|
53
|
+
original_user_id: 654321,
|
54
|
+
original_processing_day: 12,
|
55
|
+
}
|
26
56
|
)
|
27
57
|
end
|
28
58
|
|
29
|
-
puts aba.to_s
|
59
|
+
puts aba.to_s # View output
|
60
|
+
File.write("/Users/me/dd_#{Time.now.to_i}.aba", aba.to_s) # or write output to file
|
61
|
+
```
|
62
|
+
|
63
|
+
There are a few ways to create a complete set of ABA data:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# Transactions added to the defined ABA object variable
|
67
|
+
aba = Aba.batch financial_institution: 'ANZ', user_name: 'Joe Blow', user_id: 123456, process_at: 200615
|
68
|
+
aba.add_transaction bsb: '123-456', account_number: '000-123-456', amount: 50000
|
69
|
+
aba.add_transaction bsb: '456-789', account_number: '123-456-789', amount: '-10000', transaction_code: 13
|
70
|
+
|
71
|
+
# Transactions passed individually inside a block
|
72
|
+
aba = Aba.batch financial_institution: 'ANZ', user_name: 'Joe Blow', user_id: 123456, process_at: 200615 do |a|
|
73
|
+
a.add_transaction bsb: '123-456', account_number: '000-123-456', amount: 50000
|
74
|
+
a.add_transaction bsb: '456-789', account_number: '123-456-789', amount: '-10000', transaction_code: 13
|
75
|
+
end
|
76
|
+
|
77
|
+
# Transactions as an array passed to the second param of Aba.batch
|
78
|
+
aba = Aba.batch(
|
79
|
+
{ financial_institution: 'ANZ', user_name: 'Joe Blow', user_id: 123456, process_at: 200615 },
|
80
|
+
[
|
81
|
+
{ bsb: '123-456', account_number: '000-123-456', amount: 50000 },
|
82
|
+
{ bsb: '456-789', account_number: '123-456-789', amount: '-10000', transaction_code: 13 }
|
83
|
+
]
|
84
|
+
)
|
85
|
+
|
86
|
+
# NOTE: Be careful with negative transaction amounts! transaction_code will not
|
87
|
+
# be set to debit automatically!
|
30
88
|
```
|
31
89
|
|
90
|
+
Validation errors can be caught in several ways:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
# Create an ABA object with invalid character in the user_name
|
94
|
+
aba = Aba.batch(
|
95
|
+
financial_institution: "ANZ",
|
96
|
+
user_name: "Jøhn Doe",
|
97
|
+
user_id: "123456",
|
98
|
+
process_at: Time.now.strftime("%d%m%y")
|
99
|
+
)
|
100
|
+
|
101
|
+
# Add a transaction with a bad BSB
|
102
|
+
aba.add_transaction(
|
103
|
+
bsb: "abc-123",
|
104
|
+
account_number: "000123456"
|
105
|
+
)
|
106
|
+
|
107
|
+
# Is the data valid?
|
108
|
+
aba.valid?
|
109
|
+
# Returns: false
|
110
|
+
|
111
|
+
# Return a structured array of errors
|
112
|
+
puts aba.errors
|
113
|
+
# Returns:
|
114
|
+
# {:aba => ["user_name must not contain invalid characters"],
|
115
|
+
# :transactions =>
|
116
|
+
# {0 => ["bsb format is incorrect", "trace_bsb format is incorrect"]}}
|
117
|
+
```
|
118
|
+
|
119
|
+
Validation errors will stop parsing of the data to an ABA formatted string using
|
120
|
+
`to_s`. `aba.to_s` will raise a `RuntimeError` instead of returning output.
|
121
|
+
|
122
|
+
|
32
123
|
## Installation
|
33
124
|
|
34
125
|
Add this line to your application's Gemfile:
|
data/aba.gemspec
CHANGED
@@ -6,10 +6,10 @@ require 'aba/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "aba"
|
8
8
|
spec.version = Aba::VERSION
|
9
|
-
spec.authors = ["Andrey Bazhutkin"]
|
10
|
-
spec.email = ["andrey.bazhutkin@gmail.com"]
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
9
|
+
spec.authors = ["Andrey Bazhutkin", "Trevor Wistaff"]
|
10
|
+
spec.email = ["andrey.bazhutkin@gmail.com", "trev@a07.com.au"]
|
11
|
+
spec.summary = "ABA File Generator"
|
12
|
+
spec.description = "ABA (Australian Bankers Association) File Generator"
|
13
13
|
spec.homepage = "https://github.com/andrba/aba"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -18,9 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_development_dependency "bundler"
|
21
|
+
spec.add_development_dependency "bundler"
|
22
22
|
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "pry"
|
23
24
|
spec.add_development_dependency "rspec", "~> 3.0"
|
24
25
|
|
25
|
-
spec.required_ruby_version = '>=
|
26
|
+
spec.required_ruby_version = '>= 2.5.0'
|
26
27
|
end
|
data/lib/aba.rb
CHANGED
@@ -1,120 +1,12 @@
|
|
1
1
|
require "aba/version"
|
2
2
|
require "aba/validations"
|
3
|
+
require "aba/entry"
|
4
|
+
require "aba/batch"
|
5
|
+
require "aba/return"
|
3
6
|
require "aba/transaction"
|
4
7
|
|
5
8
|
class Aba
|
6
|
-
|
7
|
-
|
8
|
-
attr_accessor :bsb, :account_number, :financial_institution, :user_name, :user_id,
|
9
|
-
:description, :process_at, :name_of_remitter, :transactions
|
10
|
-
|
11
|
-
validates_presence_of :bsb, :financial_institution, :user_name, :user_id, :description, :process_at
|
12
|
-
|
13
|
-
validates_bsb :bsb
|
14
|
-
|
15
|
-
validates_max_length :account_number, 9
|
16
|
-
validates_max_length :financial_institution, 3
|
17
|
-
validates_max_length :user_name, 26
|
18
|
-
validates_max_length :user_id, 6
|
19
|
-
validates_max_length :description, 12
|
20
|
-
|
21
|
-
def initialize(attrs = {})
|
22
|
-
attrs.each do |key, value|
|
23
|
-
send("#{key}=", value)
|
24
|
-
end
|
25
|
-
|
26
|
-
self.transactions = []
|
27
|
-
|
28
|
-
yield self if block_given?
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_s
|
32
|
-
# Descriptive record
|
33
|
-
output = "#{descriptive_record}\r\n"
|
34
|
-
|
35
|
-
# Transactions records
|
36
|
-
output += @transactions.map{ |t| t.to_s }.join("\r\n")
|
37
|
-
|
38
|
-
# Batch control record
|
39
|
-
output += "\r\n#{batch_control_record}"
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def descriptive_record
|
45
|
-
# Record type
|
46
|
-
output = "0"
|
47
|
-
|
48
|
-
# Bank/State/Branch number of the funds account with a hyphen in the 4th character position. e.g. 013-999.
|
49
|
-
output += self.bsb
|
50
|
-
|
51
|
-
# Funds account number.
|
52
|
-
output += self.account_number.to_s.ljust(9, " ")
|
53
|
-
|
54
|
-
# Reserved
|
55
|
-
output += " "
|
56
|
-
|
57
|
-
# Sequence number
|
58
|
-
output += "01"
|
59
|
-
|
60
|
-
# Must contain the bank mnemonic that is associated with the BSB of the funds account. e.g. ‘ANZ’.
|
61
|
-
output += self.financial_institution[0..2].to_s
|
62
|
-
|
63
|
-
# Reserved
|
64
|
-
output += " " * 7
|
65
|
-
|
66
|
-
# Name of User supplying File as advised by User's Financial Institution
|
67
|
-
output += self.user_name.to_s.ljust(26, " ")
|
68
|
-
|
69
|
-
# Direct Entry User ID.
|
70
|
-
output += self.user_id.to_s.rjust(6, "0")
|
71
|
-
|
72
|
-
# Description of payments in the file (e.g. Payroll, Creditors etc.).
|
73
|
-
output += self.description.to_s.ljust(12, " ")
|
74
|
-
|
75
|
-
# Date and time on which the payment is to be processed.
|
76
|
-
output += self.process_at.strftime("%d%m%y%H%M")
|
77
|
-
|
78
|
-
# Reserved
|
79
|
-
output += " " * 36
|
80
|
-
end
|
81
|
-
|
82
|
-
def batch_control_record
|
83
|
-
# Record type
|
84
|
-
output = "7"
|
85
|
-
|
86
|
-
# BSB Format Filler
|
87
|
-
output += "999-999"
|
88
|
-
|
89
|
-
# Reserved
|
90
|
-
output += " " * 12
|
91
|
-
|
92
|
-
net_total_amount = 0
|
93
|
-
credit_total_amount = 0
|
94
|
-
debit_total_amount = 0
|
95
|
-
|
96
|
-
@transactions.each do |t|
|
97
|
-
net_total_amount += t.amount
|
98
|
-
credit_total_amount += t.amount if t.amount > 0
|
99
|
-
debit_total_amount += t.amount if t.amount < 0
|
100
|
-
end
|
101
|
-
|
102
|
-
# Must equal the difference between File Credit & File Debit Total Amounts. Show in cents without punctuation
|
103
|
-
output += net_total_amount.abs.to_s.rjust(10, "0")
|
104
|
-
|
105
|
-
# Batch Credit Total Amount
|
106
|
-
output += credit_total_amount.abs.to_s.rjust(10, "0")
|
107
|
-
|
108
|
-
# Batch Debit Total Amount
|
109
|
-
output += debit_total_amount.abs.to_s.rjust(10, "0")
|
110
|
-
|
111
|
-
# Reserved
|
112
|
-
output += " " * 24
|
113
|
-
|
114
|
-
# Batch Total Item Count
|
115
|
-
output += @transactions.size.to_s.rjust(6, "0")
|
116
|
-
|
117
|
-
# Reserved
|
118
|
-
output += " " * 40
|
9
|
+
def self.batch(attrs = {}, transactions = [])
|
10
|
+
Aba::Batch.new(attrs, transactions)
|
119
11
|
end
|
120
|
-
end
|
12
|
+
end
|
data/lib/aba/batch.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
class Aba
|
2
|
+
class Batch
|
3
|
+
include Aba::Validations
|
4
|
+
|
5
|
+
attr_accessor :bsb, :financial_institution, :user_name, :user_id, :description, :process_at, :entries
|
6
|
+
|
7
|
+
# BSB
|
8
|
+
validates_bsb :bsb, allow_blank: true
|
9
|
+
|
10
|
+
# Financial Institution
|
11
|
+
validates_length :financial_institution, 3
|
12
|
+
|
13
|
+
# User Name
|
14
|
+
validates_presence_of :user_name
|
15
|
+
validates_max_length :user_name, 26
|
16
|
+
validates_becs :user_name
|
17
|
+
|
18
|
+
# User ID
|
19
|
+
validates_presence_of :user_id
|
20
|
+
validates_max_length :user_id, 6
|
21
|
+
validates_integer :user_id, false
|
22
|
+
|
23
|
+
# Description
|
24
|
+
validates_max_length :description, 12
|
25
|
+
validates_becs :description
|
26
|
+
|
27
|
+
# Process at Date
|
28
|
+
validates_length :process_at, 6
|
29
|
+
validates_integer :process_at, false
|
30
|
+
|
31
|
+
|
32
|
+
def initialize(attrs = {}, transactions = [])
|
33
|
+
attrs.each do |key, value|
|
34
|
+
send("#{key}=", value)
|
35
|
+
end
|
36
|
+
|
37
|
+
@entries = []
|
38
|
+
|
39
|
+
unless transactions.nil? || transactions.empty?
|
40
|
+
transactions.to_a.each do |t|
|
41
|
+
self.add_transaction(t) unless t.nil? || t.empty?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
yield self if block_given?
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
raise RuntimeError, 'No entries present - add one using `add_transaction` or `add_return`' if entries.empty?
|
50
|
+
raise RuntimeError, 'ABA data is invalid - check the contents of `errors`' unless valid?
|
51
|
+
|
52
|
+
# Descriptive record
|
53
|
+
output = "#{descriptive_record}\r\n"
|
54
|
+
|
55
|
+
# Transactions records
|
56
|
+
output += entries.map { |t| t.to_s }.join("\r\n")
|
57
|
+
|
58
|
+
# Batch control record
|
59
|
+
output += "\r\n#{batch_control_record}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_transaction(attrs = {})
|
63
|
+
add_entry(Aba::Transaction, attrs)
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_return(attrs = {})
|
67
|
+
add_entry(Aba::Return, attrs)
|
68
|
+
end
|
69
|
+
|
70
|
+
def transactions
|
71
|
+
entries.select { |entry| entry.instance_of?(Aba::Transaction) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def transactions_valid?
|
75
|
+
!transactions.map { |t| t.valid? }.include?(false)
|
76
|
+
end
|
77
|
+
|
78
|
+
def valid?
|
79
|
+
!has_errors? && !has_entry_errors?
|
80
|
+
end
|
81
|
+
|
82
|
+
def errors
|
83
|
+
# Run validations
|
84
|
+
has_errors?
|
85
|
+
has_entry_errors?
|
86
|
+
|
87
|
+
# Build errors
|
88
|
+
all_errors = {}
|
89
|
+
all_errors[:aba] = self.error_collection unless self.error_collection.empty?
|
90
|
+
entry_error_collection = entries.each_with_index.map { |t, i| [i, t.error_collection] }.reject { |e| e[1].nil? || e[1].empty? }.to_h
|
91
|
+
all_errors[:entries] = entry_error_collection unless entry_error_collection.empty?
|
92
|
+
|
93
|
+
all_errors unless all_errors.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def add_entry(type, attrs)
|
99
|
+
(attrs.instance_of?(type) ? attrs : type.new(attrs)).tap do |entry|
|
100
|
+
entries << entry
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def has_entry_errors?
|
105
|
+
entries.map { |t| t.valid? }.include?(false)
|
106
|
+
end
|
107
|
+
|
108
|
+
def descriptive_record
|
109
|
+
# Record type
|
110
|
+
# Max: 1
|
111
|
+
# Char position: 1
|
112
|
+
output = "0"
|
113
|
+
|
114
|
+
# Optional branch number of the funds account with a hyphen in the 4th character position
|
115
|
+
# Char position: 2-18
|
116
|
+
# Max: 17
|
117
|
+
# Blank filled
|
118
|
+
output += self.bsb.nil? ? " " * 17 : self.bsb.to_s.ljust(17)
|
119
|
+
|
120
|
+
# Sequence number
|
121
|
+
# Char position: 19-20
|
122
|
+
# Max: 2
|
123
|
+
# Zero padded
|
124
|
+
output += "01"
|
125
|
+
|
126
|
+
# Name of user financial instituion
|
127
|
+
# Max: 3
|
128
|
+
# Char position: 21-23
|
129
|
+
output += self.financial_institution.to_s
|
130
|
+
|
131
|
+
# Reserved
|
132
|
+
# Max: 7
|
133
|
+
# Char position: 24-30
|
134
|
+
output += " " * 7
|
135
|
+
|
136
|
+
# Name of User supplying File
|
137
|
+
# Char position: 31-56
|
138
|
+
# Max: 26
|
139
|
+
# Full BECS character set valid
|
140
|
+
# Blank filled
|
141
|
+
output += self.user_name.to_s.ljust(26)
|
142
|
+
|
143
|
+
# Direct Entry User ID
|
144
|
+
# Char position: 57-62
|
145
|
+
# Max: 6
|
146
|
+
# Zero padded
|
147
|
+
output += self.user_id.to_s.rjust(6, "0")
|
148
|
+
|
149
|
+
# Description of payments in the file (e.g. Payroll, Creditors etc.)
|
150
|
+
# Char position: 63-74
|
151
|
+
# Max: 12
|
152
|
+
# Full BECS character set valid
|
153
|
+
# Blank filled
|
154
|
+
output += self.description.to_s.ljust(12)
|
155
|
+
|
156
|
+
# Date on which the payment is to be processed
|
157
|
+
# Char position: 75-80
|
158
|
+
# Max: 6
|
159
|
+
output += self.process_at.to_s.rjust(6, "0")
|
160
|
+
|
161
|
+
# Reserved
|
162
|
+
# Max: 40
|
163
|
+
# Char position: 81-120
|
164
|
+
output += " " * 40
|
165
|
+
end
|
166
|
+
|
167
|
+
def batch_control_record
|
168
|
+
net_total_amount = 0
|
169
|
+
credit_total_amount = 0
|
170
|
+
debit_total_amount = 0
|
171
|
+
|
172
|
+
entries.each do |t|
|
173
|
+
net_total_amount += t.amount.to_i
|
174
|
+
credit_total_amount += t.amount.to_i if t.amount.to_i > 0
|
175
|
+
debit_total_amount += t.amount.to_i if t.amount.to_i < 0
|
176
|
+
end
|
177
|
+
|
178
|
+
# Record type
|
179
|
+
# Max: 1
|
180
|
+
# Char position: 1
|
181
|
+
output = "7"
|
182
|
+
|
183
|
+
# BSB Format Filler
|
184
|
+
# Max: 7
|
185
|
+
# Char position: 2-8
|
186
|
+
output += "999-999"
|
187
|
+
|
188
|
+
# Reserved
|
189
|
+
# Max: 12
|
190
|
+
# Char position: 9-20
|
191
|
+
output += " " * 12
|
192
|
+
|
193
|
+
# Net total
|
194
|
+
# Max: 10
|
195
|
+
# Char position: 21-30
|
196
|
+
output += net_total_amount.abs.to_s.rjust(10, "0")
|
197
|
+
|
198
|
+
# Credit Total Amount
|
199
|
+
# Max: 10
|
200
|
+
# Char position: 31-40
|
201
|
+
output += credit_total_amount.abs.to_s.rjust(10, "0")
|
202
|
+
|
203
|
+
# Debit Total Amount
|
204
|
+
# Max: 10
|
205
|
+
# Char position: 41-50
|
206
|
+
output += debit_total_amount.abs.to_s.rjust(10, "0")
|
207
|
+
|
208
|
+
# Reserved
|
209
|
+
# Max: 24
|
210
|
+
# Char position: 51-74
|
211
|
+
output += " " * 24
|
212
|
+
|
213
|
+
# Total Item Count
|
214
|
+
# Max: 6
|
215
|
+
# Char position: 75-80
|
216
|
+
output += entries.size.to_s.rjust(6, "0")
|
217
|
+
|
218
|
+
# Reserved
|
219
|
+
# Max: 40
|
220
|
+
# Char position: 81-120
|
221
|
+
output += " " * 40
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|