lucabook 0.2.15 → 0.2.21
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/exe/luca-book +99 -19
- data/lib/luca_book.rb +2 -0
- data/lib/luca_book/console.rb +2 -0
- data/lib/luca_book/dict.rb +10 -3
- data/lib/luca_book/import.rb +10 -7
- data/lib/luca_book/list.rb +92 -23
- data/lib/luca_book/setup.rb +16 -1
- data/lib/luca_book/state.rb +253 -118
- data/lib/luca_book/templates/base-jp.xbrl.erb +78 -0
- data/lib/luca_book/templates/dict-en.tsv +35 -31
- data/lib/luca_book/templates/dict-jp.tsv +163 -145
- data/lib/luca_book/util.rb +46 -0
- data/lib/luca_book/version.rb +1 -1
- metadata +4 -3
- data/lib/luca_book/report.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f7366698bee6b770fbae39f8fe650e1f460b04dec25c8036c84013f970adaa3
|
4
|
+
data.tar.gz: 8ecbf412b31f001f0cfa2de27ceb879463d17f28e3db552770866b44c0b73114
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e30fabd50119ad470c90512bcf066b3992b5df2d67139f437a5f4336d73c843fb65dab2a70b5914c190155de68f82ec722840e0f056079061634f77bb5da4964
|
7
|
+
data.tar.gz: 3e8775200e05f8bfe0923b53690fa5245441ea4d71768246a7309ee503294d847a466e82da85568d3071f47eccd4f9783a79199b4d4eb630c961de84488a31ed
|
data/exe/luca-book
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
|
3
|
+
require 'json'
|
3
4
|
require 'optparse'
|
4
5
|
require 'luca_book'
|
5
6
|
|
6
|
-
|
7
|
-
class Journal
|
7
|
+
class LucaCmd
|
8
|
+
class Journal < LucaCmd
|
8
9
|
def self.import(args, params)
|
9
10
|
if params['config']
|
10
11
|
LucaBook::Import.new(args[0], params['config']).import_csv
|
@@ -12,31 +13,66 @@ module LucaCmd
|
|
12
13
|
LucaBook::Import.import_json(STDIN.read)
|
13
14
|
else
|
14
15
|
puts 'Usage: luca-book import -c import_config'
|
16
|
+
exit 1
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
def self.list(args, params)
|
21
|
+
args = gen_range(params[:n] || 1) if args.empty?
|
19
22
|
if params['code']
|
20
|
-
LucaBook::List.term(*args, code: params['code']).
|
21
|
-
elsif args.length > 0
|
22
|
-
LucaBook::List.term(*args).flat_list.to_yaml
|
23
|
+
render(LucaBook::List.term(*args, code: params['code']).list_on_code, params)
|
23
24
|
else
|
24
|
-
|
25
|
+
render(LucaBook::List.term(*args).list_journals, params)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.stats(args, params)
|
30
|
+
args = gen_range(params[:n]) if args.empty?
|
31
|
+
if params['code']
|
32
|
+
render(LucaBook::State.by_code(params['code'], *args), params)
|
33
|
+
else
|
34
|
+
render(LucaBook::State.term(*args).stats(params[:level]), params)
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
|
29
|
-
class Report
|
39
|
+
class Report < LucaCmd
|
30
40
|
def self.balancesheet(args, params)
|
31
|
-
|
41
|
+
level = params[:level] || 3
|
42
|
+
legal = params[:legal] || false
|
43
|
+
args = gen_range(params[:n] || 1) if args.empty?
|
44
|
+
render(LucaBook::State.term(*args).bs(level, legal: legal), params)
|
32
45
|
end
|
33
46
|
|
34
47
|
def self.profitloss(args, params)
|
35
|
-
|
48
|
+
level = params[:level] || 2
|
49
|
+
args = gen_range(params[:n]) if args.empty?
|
50
|
+
render(LucaBook::State.term(*args).pl(level), params)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.gen_range(count)
|
55
|
+
count ||= 3
|
56
|
+
today = Date.today
|
57
|
+
start = today.prev_month(count - 1)
|
58
|
+
[start.year, start.month, today.year, today.month]
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.render(dat, params)
|
62
|
+
case params[:output]
|
63
|
+
when 'json'
|
64
|
+
puts JSON.dump(dat)
|
65
|
+
when 'nu'
|
66
|
+
LucaSupport::View.nushell(YAML.dump(dat))
|
67
|
+
else
|
68
|
+
puts YAML.dump(dat)
|
36
69
|
end
|
37
70
|
end
|
38
71
|
end
|
39
72
|
|
73
|
+
def new_pj(args = nil, params = {})
|
74
|
+
LucaBook::Setup.create_project params['country'], args[0]
|
75
|
+
end
|
40
76
|
|
41
77
|
LucaRecord::Base.valid_project?
|
42
78
|
cmd = ARGV.shift
|
@@ -48,41 +84,85 @@ when /journals?/, 'j'
|
|
48
84
|
case subcmd
|
49
85
|
when 'import'
|
50
86
|
OptionParser.new do |opt|
|
51
|
-
opt.banner = 'Usage: luca import filepath'
|
52
|
-
opt.on('-c', '--config VAL', 'import definition'){|v| params['config'] = v }
|
53
|
-
opt.on('-j', '--json', 'import via json format'){|_v| params['json'] = true }
|
87
|
+
opt.banner = 'Usage: luca-book journals import [options] filepath'
|
88
|
+
opt.on('-c', '--config VAL', 'import definition'){ |v| params['config'] = v }
|
89
|
+
opt.on('-j', '--json', 'import via json format'){ |_v| params['json'] = true }
|
54
90
|
args = opt.parse!(ARGV)
|
55
91
|
LucaCmd::Journal.import(args, params)
|
56
92
|
end
|
57
93
|
when 'list'
|
58
94
|
OptionParser.new do |opt|
|
59
|
-
opt.banner = 'Usage: luca list [
|
95
|
+
opt.banner = 'Usage: luca-book journals list [options] [YYYY M]'
|
60
96
|
opt.on('-c', '--code VAL', 'search with code') { |v| params['code'] = v }
|
97
|
+
opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
|
98
|
+
opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
|
99
|
+
opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
|
61
100
|
opt.on_tail('List records. If you specify code and/or month, search on each criteria.')
|
62
101
|
args = opt.parse!(ARGV)
|
63
102
|
LucaCmd::Journal.list(args, params)
|
64
103
|
end
|
104
|
+
when 'stats'
|
105
|
+
OptionParser.new do |opt|
|
106
|
+
opt.banner = 'Usage: luca-book journals stats [options] [YYYY M]'
|
107
|
+
opt.on('-c', '--code VAL', 'search with code') { |v| params['code'] = v }
|
108
|
+
opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
|
109
|
+
opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
|
110
|
+
opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
|
111
|
+
args = opt.parse!(ARGV)
|
112
|
+
LucaCmd::Journal.stats(args, params)
|
113
|
+
end
|
114
|
+
else
|
115
|
+
puts 'Proper subcommand needed.'
|
116
|
+
puts
|
117
|
+
puts 'Usage: luca-book (j|journal[s]) subcommand [options] [YYYY M YYYY M]'
|
118
|
+
puts ' import: import journals from JSON/TSV'
|
119
|
+
puts ' list: list journals'
|
120
|
+
puts ' stats: list account statistics'
|
121
|
+
exit 1
|
122
|
+
end
|
123
|
+
when 'new'
|
124
|
+
OptionParser.new do |opt|
|
125
|
+
opt.banner = 'Usage: luca-book new [options] Dir'
|
126
|
+
opt.on('-c', '--country VAL', 'specify country code') { |v| params['coountry'] = v }
|
127
|
+
args = opt.parse(ARGV)
|
128
|
+
new_pj(args, params)
|
65
129
|
end
|
66
130
|
when /reports?/, 'r'
|
67
131
|
subcmd = ARGV.shift
|
68
132
|
case subcmd
|
69
133
|
when 'bs'
|
70
134
|
OptionParser.new do |opt|
|
71
|
-
opt.banner = 'Usage: luca-book reports bs'
|
135
|
+
opt.banner = 'Usage: luca-book reports bs [options] [YYYY M]'
|
136
|
+
opt.on('-l', '--level VAL', 'account level') { |v| params[:level] = v.to_i }
|
137
|
+
opt.on('--legal', 'show legal mandatory account') { |_v| params[:legal] = true }
|
138
|
+
opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
|
139
|
+
opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
|
72
140
|
args = opt.parse!(ARGV)
|
73
141
|
LucaCmd::Report.balancesheet(args, params)
|
74
142
|
end
|
75
143
|
when 'pl'
|
76
144
|
OptionParser.new do |opt|
|
77
|
-
opt.banner = 'Usage: luca-book reports pl'
|
145
|
+
opt.banner = 'Usage: luca-book reports pl [options] [YYYY M YYYY M]'
|
146
|
+
opt.on('-l', '--level VAL', 'account level') { |v| params[:level] = v.to_i }
|
147
|
+
opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
|
148
|
+
opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
|
149
|
+
opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
|
78
150
|
args = opt.parse!(ARGV)
|
79
151
|
LucaCmd::Report.profitloss(args, params)
|
80
152
|
end
|
153
|
+
else
|
154
|
+
puts 'Proper subcommand needed.'
|
155
|
+
puts
|
156
|
+
puts 'Usage: luca-book (r|report[s]) (bs|pl) [options] YYYY M'
|
157
|
+
puts ' bs: show balance sheet'
|
158
|
+
puts ' pl: show statement of income'
|
159
|
+
exit 1
|
81
160
|
end
|
82
|
-
|
83
|
-
puts '
|
161
|
+
else
|
162
|
+
puts 'Proper subcommand needed.'
|
163
|
+
puts
|
164
|
+
puts 'Usage: luca-book (j[ournals]|r[eports]) subcommand'
|
84
165
|
puts ' journals: operate journal records'
|
85
166
|
puts ' reports: show reports'
|
86
|
-
|
87
|
-
puts 'Invalid subcommand'
|
167
|
+
exit 1
|
88
168
|
end
|
data/lib/luca_book.rb
CHANGED
@@ -5,9 +5,11 @@ require 'luca_record'
|
|
5
5
|
require 'luca_book/version'
|
6
6
|
|
7
7
|
module LucaBook
|
8
|
+
autoload :Dict, 'luca_book/dict'
|
8
9
|
autoload :Import, 'luca_book/import'
|
9
10
|
autoload :Journal, 'luca_book/journal'
|
10
11
|
autoload :List, 'luca_book/list'
|
11
12
|
autoload :Setup, 'luca_book/setup'
|
12
13
|
autoload :State, 'luca_book/state'
|
14
|
+
autoload :Util, 'luca_book/util'
|
13
15
|
end
|
data/lib/luca_book/console.rb
CHANGED
@@ -29,6 +29,7 @@ class LucaBookConsole
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
# TODO: deprecated. accumulate_all() already removed.
|
32
33
|
def bs
|
33
34
|
target = []
|
34
35
|
report = []
|
@@ -56,6 +57,7 @@ class LucaBookConsole
|
|
56
57
|
puts "---- ----"
|
57
58
|
end
|
58
59
|
|
60
|
+
# TODO: deprecated. accumulate_all() already removed.
|
59
61
|
def pl
|
60
62
|
target = []
|
61
63
|
report = []
|
data/lib/luca_book/dict.rb
CHANGED
@@ -2,12 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'luca_support/config'
|
4
4
|
require 'luca_record/dict'
|
5
|
+
require 'date'
|
6
|
+
require 'pathname'
|
5
7
|
|
6
8
|
module LucaBook
|
7
9
|
class Dict < LucaRecord::Dict
|
10
|
+
def self.latest_balance
|
11
|
+
dict_dir = Pathname(LucaSupport::Config::Pjdir) / 'data' / 'balance'
|
12
|
+
# TODO: search latest balance dictionary
|
13
|
+
load_tsv_dict(dict_dir / 'start.tsv')
|
14
|
+
end
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
16
|
+
def self.issue_date(obj)
|
17
|
+
Date.parse(obj.dig('_date', :label))
|
18
|
+
end
|
12
19
|
end
|
13
20
|
end
|
data/lib/luca_book/import.rb
CHANGED
@@ -9,14 +9,15 @@ require 'luca_record'
|
|
9
9
|
|
10
10
|
module LucaBook
|
11
11
|
class Import
|
12
|
-
DEBIT_DEFAULT = '
|
13
|
-
CREDIT_DEFAULT = '
|
12
|
+
DEBIT_DEFAULT = '10XX'
|
13
|
+
CREDIT_DEFAULT = '50XX'
|
14
14
|
|
15
15
|
def initialize(path, dict)
|
16
16
|
raise 'no such file' unless FileTest.file?(path)
|
17
17
|
|
18
18
|
@target_file = path
|
19
19
|
# TODO: yaml need to be configurable
|
20
|
+
@dict_name = dict
|
20
21
|
@dict = LucaRecord::Dict.new("import-#{dict}.yaml")
|
21
22
|
@code_map = LucaRecord::Dict.reverse(LucaRecord::Dict.load('base.tsv'))
|
22
23
|
@config = @dict.csv_config if dict
|
@@ -59,7 +60,7 @@ module LucaBook
|
|
59
60
|
if @config[:type] == 'single'
|
60
61
|
LucaBook::Journal.create(parse_single(row))
|
61
62
|
elsif @config[:type] == 'double'
|
62
|
-
p parse_double(row)
|
63
|
+
p parse_double(row) # TODO: Not implemented yet
|
63
64
|
else
|
64
65
|
p row
|
65
66
|
end
|
@@ -85,7 +86,7 @@ module LucaBook
|
|
85
86
|
d['date'] = parse_date(row)
|
86
87
|
if row.dig(@config[:credit_value])&.empty?
|
87
88
|
d['debit'] = [
|
88
|
-
{ 'code' => search_code(row[@config[:label]],
|
89
|
+
{ 'code' => search_code(row[@config[:label]], @config.dig(:default_debit)) || DEBIT_DEFAULT }
|
89
90
|
]
|
90
91
|
d['credit'] = [
|
91
92
|
{ 'code' => @code_map.dig(@config[:counter_label]) }
|
@@ -95,12 +96,13 @@ module LucaBook
|
|
95
96
|
{ 'code' => @code_map.dig(@config[:counter_label]) }
|
96
97
|
]
|
97
98
|
d['credit'] = [
|
98
|
-
{ 'code' => search_code(row[@config[:label]],
|
99
|
+
{ 'code' => search_code(row[@config[:label]], @config.dig(:default_credit)) || CREDIT_DEFAULT }
|
99
100
|
]
|
100
101
|
end
|
101
102
|
d['debit'][0]['value'] = value
|
102
103
|
d['credit'][0]['value'] = value
|
103
104
|
d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
|
105
|
+
d['x-editor'] = "LucaBook::Import/#{@dict_name}"
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
@@ -111,14 +113,15 @@ module LucaBook
|
|
111
113
|
{}.tap do |d|
|
112
114
|
d['date'] = parse_date(row)
|
113
115
|
d['debit'] = {
|
114
|
-
'code' => search_code(row[@config[:
|
116
|
+
'code' => search_code(row[@config[:label]], @config.dig(:default_debit)) || DEBIT_DEFAULT,
|
115
117
|
'value' => row.dig(@config[:debit_value])
|
116
118
|
}
|
117
119
|
d['credit'] = {
|
118
|
-
'code' => search_code(row[@config[:
|
120
|
+
'code' => search_code(row[@config[:label]], @config.dig(:default_credit)) || CREDIT_DEFAULT,
|
119
121
|
'value' => row.dig(@config[:credit_value])
|
120
122
|
}
|
121
123
|
d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
|
124
|
+
d['x-editor'] = "LucaBook::Import/#{@dict_name}"
|
122
125
|
end
|
123
126
|
end
|
124
127
|
|
data/lib/luca_book/list.rb
CHANGED
@@ -13,8 +13,10 @@ module LucaBook
|
|
13
13
|
class List < LucaBook::Journal
|
14
14
|
@dirname = 'journals'
|
15
15
|
|
16
|
-
def initialize(data)
|
16
|
+
def initialize(data, start_date, code = nil)
|
17
17
|
@data = data
|
18
|
+
@code = code
|
19
|
+
@start = start_date
|
18
20
|
@dict = LucaRecord::Dict.load('base.tsv')
|
19
21
|
end
|
20
22
|
|
@@ -26,44 +28,111 @@ module LucaBook
|
|
26
28
|
[:debit, :credit].map { |key| serialize_on_key(dat[key], :code) }.flatten.include?(code)
|
27
29
|
end
|
28
30
|
end
|
29
|
-
new data
|
31
|
+
new data, Date.new(from_year.to_i, from_month.to_i, 1), code
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
def list_on_code
|
35
|
+
calc_code
|
36
|
+
convert_label
|
37
|
+
@data = [code_header] + @data.map do |dat|
|
38
|
+
date, txid = LucaSupport::Code.decode_id(dat[:id])
|
39
|
+
{}.tap do |res|
|
40
|
+
res['code'] = dat[:code]
|
41
|
+
res['date'] = date
|
42
|
+
res['no'] = txid
|
43
|
+
res['id'] = dat[:id]
|
44
|
+
res['diff'] = dat[:diff]
|
45
|
+
res['balance'] = dat[:balance]
|
46
|
+
res['counter_code'] = dat[:counter_code].length == 1 ? dat[:counter_code].first : dat[:counter_code]
|
47
|
+
res['note'] = dat[:note]
|
48
|
+
end
|
36
49
|
end
|
37
|
-
|
50
|
+
readable(@data)
|
38
51
|
end
|
39
52
|
|
40
|
-
def
|
53
|
+
def list_journals
|
41
54
|
convert_label
|
42
55
|
@data = @data.map do |dat|
|
43
|
-
|
44
|
-
|
45
|
-
date
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
res['credit_amount'] = dat[:credit][i][:amount] if dat[:credit][i]
|
54
|
-
res['note'] = dat[:note]
|
55
|
-
end
|
56
|
+
date, txid = LucaSupport::Code.decode_id(dat[:id])
|
57
|
+
{}.tap do |res|
|
58
|
+
res['date'] = date
|
59
|
+
res['no'] = txid
|
60
|
+
res['id'] = dat[:id]
|
61
|
+
res['debit_code'] = dat[:debit].length == 1 ? dat[:debit][0][:code] : dat[:debit].map { |d| d[:code] }
|
62
|
+
res['debit_amount'] = dat[:debit].inject(0) { |sum, d| sum + d[:amount] }
|
63
|
+
res['credit_code'] = dat[:credit].length == 1 ? dat[:credit][0][:code] : dat[:credit].map { |d| d[:code] }
|
64
|
+
res['credit_amount'] = dat[:credit].inject(0) { |sum, d| sum + d[:amount] }
|
65
|
+
res['note'] = dat[:note]
|
56
66
|
end
|
57
|
-
end
|
58
|
-
|
67
|
+
end
|
68
|
+
readable(@data)
|
69
|
+
end
|
70
|
+
|
71
|
+
def accumulate_code
|
72
|
+
@data.inject(BigDecimal('0')) do |sum, dat|
|
73
|
+
sum + Util.diff_by_code(dat[:debit], @code) - Util.diff_by_code(dat[:credit], @code)
|
74
|
+
end
|
59
75
|
end
|
60
76
|
|
61
77
|
def to_yaml
|
62
78
|
YAML.dump(LucaSupport::Code.readable(@data)).tap { |data| puts data }
|
63
79
|
end
|
64
80
|
|
81
|
+
private
|
82
|
+
|
83
|
+
def set_balance
|
84
|
+
return BigDecimal('0') if @code.nil? || /^[A-H]/.match(@code)
|
85
|
+
|
86
|
+
balance_dict = Dict.latest_balance
|
87
|
+
start_balance = BigDecimal(balance_dict.dig(@code.to_s, :balance) || '0')
|
88
|
+
start = Dict.issue_date(balance_dict)&.next_month
|
89
|
+
last = @start.prev_month
|
90
|
+
if last.year >= start.year && last.month >= start.month
|
91
|
+
start_balance + self.class.term(start.year, start.month, last.year, last.month, code: @code).accumulate_code
|
92
|
+
else
|
93
|
+
start_balance
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def calc_code
|
98
|
+
@balance = set_balance
|
99
|
+
if @code
|
100
|
+
balance = @balance
|
101
|
+
@data.each do |dat|
|
102
|
+
dat[:diff] = Util.diff_by_code(dat[:debit], @code) - Util.diff_by_code(dat[:credit], @code)
|
103
|
+
balance += dat[:diff]
|
104
|
+
dat[:balance] = balance
|
105
|
+
dat[:code] = @code
|
106
|
+
counter = dat[:diff] * Util.pn_debit(@code) > 0 ? :credit : :debit
|
107
|
+
dat[:counter_code] = dat[counter].map { |d| d[:code] }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def convert_label
|
114
|
+
@data.each do |dat|
|
115
|
+
if @code
|
116
|
+
dat[:code] = "#{dat[:code]} #{@dict.dig(dat[:code], :label)}"
|
117
|
+
dat[:counter_code] = dat[:counter_code].map { |counter| "#{counter} #{@dict.dig(counter, :label)}" }
|
118
|
+
else
|
119
|
+
dat[:debit].each { |debit| debit[:code] = "#{debit[:code]} #{@dict.dig(debit[:code], :label)}" }
|
120
|
+
dat[:credit].each { |credit| credit[:code] = "#{credit[:code]} #{@dict.dig(credit[:code], :label)}" }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
65
126
|
def dict
|
66
127
|
LucaBook::Dict::Data
|
67
128
|
end
|
129
|
+
|
130
|
+
def code_header
|
131
|
+
{}.tap do |h|
|
132
|
+
%w[code date no id diff balance counter_code note].each do |k|
|
133
|
+
h[k] = k == 'balance' ? @balance : ''
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
68
137
|
end
|
69
138
|
end
|