rfix 1.0.15 → 1.1.0.pre.147
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/.gitignore +5 -0
- data/.rspec +0 -1
- data/.rubocop.yml +46 -31
- data/.travis.yml +5 -12
- data/Gemfile.base +10 -3
- data/Gemfile.base.lock +172 -0
- data/Gemfile.lock +28 -7
- data/Guardfile +1 -1
- data/Makefile +4 -13
- data/Rakefile +16 -95
- data/ci/Gemfile.rubocop-0.80.lock +16 -1
- data/ci/Gemfile.rubocop-0.81.lock +16 -1
- data/ci/Gemfile.rubocop-0.82.lock +16 -1
- data/ci/Gemfile.rubocop-0.83.lock +19 -4
- data/ci/Gemfile.rubocop-0.84.lock +19 -4
- data/ci/Gemfile.rubocop-0.85.1.lock +19 -4
- data/ci/Gemfile.rubocop-0.85.lock +16 -1
- data/exe/rfix +18 -144
- data/lib/rfix.rb +10 -3
- data/lib/rfix/box.rb +112 -0
- data/lib/rfix/branch.rb +30 -0
- data/lib/rfix/branches/base.rb +29 -0
- data/lib/rfix/branches/head.rb +11 -0
- data/lib/rfix/branches/main.rb +33 -0
- data/lib/rfix/branches/name.rb +21 -0
- data/lib/rfix/branches/reference.rb +19 -0
- data/lib/rfix/branches/upstream.rb +11 -0
- data/lib/rfix/cmd.rb +9 -14
- data/lib/rfix/commands/all.rb +26 -0
- data/lib/rfix/commands/branch.rb +15 -0
- data/lib/rfix/commands/extensions/options.rb +8 -0
- data/lib/rfix/commands/help.rb +7 -0
- data/lib/rfix/commands/helper/args.rb +137 -0
- data/lib/rfix/commands/helper/help.rb +6 -0
- data/lib/rfix/commands/helper/loader.rb +6 -0
- data/lib/rfix/commands/helper/option.rb +0 -0
- data/lib/rfix/commands/helper/params.rb +0 -0
- data/lib/rfix/commands/helper/rubocop.rb +17 -0
- data/lib/rfix/commands/info.rb +30 -0
- data/lib/rfix/commands/lint.rb +23 -0
- data/lib/rfix/commands/local.rb +12 -0
- data/lib/rfix/commands/origin.rb +19 -0
- data/lib/rfix/commands/setup.rb +29 -0
- data/lib/rfix/commands/welcome.rb +24 -0
- data/lib/rfix/deleted.rb +13 -0
- data/lib/rfix/error.rb +2 -0
- data/lib/rfix/extensions/extensions.rb +4 -26
- data/lib/rfix/extensions/offense.rb +2 -1
- data/lib/rfix/extensions/string.rb +8 -0
- data/lib/rfix/file.rb +46 -0
- data/lib/rfix/file_cache.rb +59 -0
- data/lib/rfix/formatter.rb +37 -10
- data/lib/rfix/git_helper.rb +13 -1
- data/lib/rfix/log.rb +104 -7
- data/lib/rfix/no_file.rb +13 -0
- data/lib/rfix/rake/paths.rb +50 -0
- data/lib/rfix/rake/support.rb +75 -0
- data/lib/rfix/repository.rb +201 -0
- data/lib/rfix/rfix.rb +7 -198
- data/lib/rfix/tracked.rb +76 -0
- data/lib/rfix/tracked_file.rb +1 -1
- data/lib/rfix/untracked.rb +13 -0
- data/lib/rfix/version.rb +1 -1
- data/path.rb +7 -0
- data/rfix.gemspec +6 -2
- data/rugged.rb +206 -0
- data/tasks/bump.rake +11 -0
- data/tasks/bundle.rake +17 -0
- data/tasks/complex.rake +54 -0
- data/tasks/simple.rake +58 -0
- data/tasks/travis.rake +74 -0
- data/tasks/vendor.rake +34 -0
- metadata +136 -13
- data/file.rb +0 -1
- data/lib/rfix/gem_helper.rb +0 -12
- data/lib/rfix/git_file.rb +0 -36
- data/lib/rfix/rake_helper.rb +0 -56
- data/lib/rfix/untracked_file.rb +0 -13
@@ -0,0 +1,23 @@
|
|
1
|
+
r_args = []
|
2
|
+
|
3
|
+
helper("help", binding)
|
4
|
+
helper("rubocop", binding)
|
5
|
+
helper("args", binding)
|
6
|
+
|
7
|
+
summary "Lints commits and untracked files not yet pushed to upstream"
|
8
|
+
usage "rfix lint [opts] [path ..]"
|
9
|
+
description "Lint (read-only) files"
|
10
|
+
|
11
|
+
|
12
|
+
run do |opts, args, _cmd|
|
13
|
+
opts[:dry] = true
|
14
|
+
opts[:untracked] = true
|
15
|
+
|
16
|
+
if main = opts[:"main-branch"]
|
17
|
+
branch = Rfix::Branch::Name.new(main)
|
18
|
+
else
|
19
|
+
branch = Rfix::Branch::MAIN
|
20
|
+
end
|
21
|
+
|
22
|
+
setup(r_args, opts, args, files: args.each.to_a, reference: branch)
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
r_args = []
|
2
|
+
|
3
|
+
helper("help", binding)
|
4
|
+
helper("rubocop", binding)
|
5
|
+
helper("args", binding)
|
6
|
+
|
7
|
+
summary "Auto-fixes commits not yet pushed to upstream"
|
8
|
+
usage "rfix local [opts] [path ..]"
|
9
|
+
|
10
|
+
run do |opts, args, _cmd|
|
11
|
+
setup(r_args, opts, args, files: args.each.to_a, reference: Rfix::Branch::UPSTREAM)
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
r_args = []
|
2
|
+
|
3
|
+
helper("help", binding)
|
4
|
+
helper("rubocop", binding)
|
5
|
+
helper("args", binding)
|
6
|
+
|
7
|
+
summary "Auto-fixes commits between HEAD and origin branch"
|
8
|
+
usage "rfix origin [opts] [path ..]"
|
9
|
+
|
10
|
+
run do |opts, args, _cmd|
|
11
|
+
if main = opts[:"main-branch"]
|
12
|
+
branch = Rfix::Branch::Name.new(main)
|
13
|
+
else
|
14
|
+
branch = Rfix::Branch::MAIN
|
15
|
+
end
|
16
|
+
|
17
|
+
# say "Using {{red:#{branch}}} as main branch"
|
18
|
+
setup(r_args, opts, args, files: args.each.to_a, reference: branch)
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
helper("help", binding)
|
2
|
+
|
3
|
+
option :r, :root, "{{*}} Project root path", default: Dir.pwd, argument: :required
|
4
|
+
option :b, :"main-branch", "{{*}} Branch to use", argument: :optional
|
5
|
+
|
6
|
+
summary "Sets the default branch for {{command:rfix local}}"
|
7
|
+
|
8
|
+
def set_branch(root_path, branch)
|
9
|
+
Rfix::Branch::Main.set(branch, at: root_path)
|
10
|
+
say "Main branch was set to {{italic:#{branch}}}"
|
11
|
+
end
|
12
|
+
|
13
|
+
run do |opts, _args|
|
14
|
+
if branch = Rfix::Branch::Main.get(at: opts[:root])
|
15
|
+
say "Current main branch set to {{info:#{branch}}}"
|
16
|
+
end
|
17
|
+
|
18
|
+
if branch = opts[:"main-branch"]
|
19
|
+
next set_branch(opts[:root], branch)
|
20
|
+
end
|
21
|
+
|
22
|
+
CLI::UI::Prompt.ask("Which one is your main branch?") do |handler|
|
23
|
+
Rfix::Branch.local(at: opts[:root]).each do |branch|
|
24
|
+
handler.option(branch) do |selection|
|
25
|
+
set_branch(opts[:root], selection)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
r_args = []
|
2
|
+
|
3
|
+
helper("help", binding)
|
4
|
+
|
5
|
+
summary "This is how you get started with {{command:rfix}}"
|
6
|
+
|
7
|
+
run do |_opts, _args, _cmd|
|
8
|
+
indent = " " * 2
|
9
|
+
prt "{{v}} Thank you for installing {{green:rfix v#{Rfix::VERSION}}}!\n"
|
10
|
+
prt ""
|
11
|
+
prt "{{i}} Run {{command:rfix help}} for avalible commands or any of the following to get started:"
|
12
|
+
prt ""
|
13
|
+
prt "#{indent}{{command:$ rfix local}} {{italic:# Auto-fixes commits not yet pushed to upstream}}"
|
14
|
+
prt "#{indent}{{command:$ rfix origin}} {{italic:# Auto-fixes commits between HEAD and origin branch}}"
|
15
|
+
prt "#{indent}{{command:$ rfix lint}} {{italic:# Lints commits and untracked files not yet pushed to upstream}}"
|
16
|
+
prt ""
|
17
|
+
prt "{{*}} {{bold:ProTip:}} Append {{command:--dry}} to run {{command:rfix}} in {{warning:read-only}} mode"
|
18
|
+
prt ""
|
19
|
+
prt "{{i}} {{bold:Issues}} {{italic:https://github.com/oleander/rfix-rb/issues}}"
|
20
|
+
prt "{{i}} {{bold:Readme}} {{italic:https://github.com/oleander/rfix-rb/blob/master/README.md}}"
|
21
|
+
prt "{{i}} {{bold:Travis}} {{italic:https://travis-ci.org/github/oleander/rfix-rb}}"
|
22
|
+
prt ""
|
23
|
+
prt "{{italic:~ Linus}}\n"
|
24
|
+
end
|
data/lib/rfix/deleted.rb
ADDED
data/lib/rfix/error.rb
ADDED
@@ -2,39 +2,17 @@
|
|
2
2
|
|
3
3
|
require "rubocop"
|
4
4
|
require "rainbow"
|
5
|
+
require "rfix/log"
|
5
6
|
|
6
7
|
module Rfix::Ext
|
7
8
|
module CommentConfig
|
9
|
+
include Rfix::Log # TODO: Remove
|
8
10
|
# Called by RuboCop on every line to see
|
9
11
|
# if its suppose to run against it or not
|
10
12
|
def cop_enabled_at_line?(_cop, line)
|
11
13
|
Rfix.enabled?(processed_source.file_path, line) && super
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
module Runner
|
16
|
-
# Called _after_ @source has been 'auto fixed' by Rubocop
|
17
|
-
def check_for_infinite_loop(source, offences)
|
18
|
-
# rubocop:disable Style/Semicolon
|
19
|
-
Rfix.refresh!(source); super
|
20
|
-
# rubocop:enable Style/Semicolon
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module Options
|
25
|
-
# Appends custom --args to RuboCop CLI
|
26
|
-
def define_options
|
27
|
-
super.tap do |options|
|
28
|
-
@ons.each do |args, block|
|
29
|
-
option(options, *args, &block)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Helper method used by rfix to append cli --args to Rubocop
|
35
|
-
def on(*args, &block)
|
36
|
-
@ons ||= []
|
37
|
-
@ons += [[args, block]]
|
14
|
+
rescue StandardError
|
15
|
+
say_abort "[Rfix::Enabled] #{$ERROR_INFO}"
|
38
16
|
end
|
39
17
|
end
|
40
18
|
end
|
data/lib/rfix/file.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "rugged"
|
2
|
+
require "shellwords"
|
3
|
+
require "digest"
|
4
|
+
require "listen"
|
5
|
+
|
6
|
+
class Rfix::File < Struct.new(:path, :repo, :ref)
|
7
|
+
include Rfix::Log
|
8
|
+
|
9
|
+
def initialize(path, repo, ref)
|
10
|
+
# check_absolute!(path)
|
11
|
+
super(path, repo, ref)
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_absolute!(path)
|
15
|
+
if Pathname.new(path).absolute?
|
16
|
+
say_abort "Path must be relative #{path}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def include?(_)
|
21
|
+
raise Rfix::Error.new("#include? not implemented")
|
22
|
+
end
|
23
|
+
|
24
|
+
def refresh!
|
25
|
+
raise Rfix::Error.new("#refresh! not implemented")
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
raise Rfix::Error.new("#inspect not implemented")
|
30
|
+
end
|
31
|
+
|
32
|
+
def git_path
|
33
|
+
@git_path ||= Pathname.new(repo.workdir)
|
34
|
+
end
|
35
|
+
|
36
|
+
def absolute_path
|
37
|
+
path
|
38
|
+
# @absolute_path ||= to_abs(path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_abs(path)
|
42
|
+
File.join(repo.workdir, path)
|
43
|
+
end
|
44
|
+
|
45
|
+
alias to_s path
|
46
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class FileCache
|
2
|
+
attr_reader :root_path
|
3
|
+
include Rfix::Log
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
@files = Hash.new
|
7
|
+
@paths = Hash.new
|
8
|
+
@root_path = path
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(file)
|
12
|
+
key = normalized_file_path(file)
|
13
|
+
|
14
|
+
if @files.key?(key)
|
15
|
+
return say_debug("File already exists with path {{error:#{file.path}}} using #{key}")
|
16
|
+
end
|
17
|
+
|
18
|
+
say_debug("Adding file with path {{green:#{file.path}}} using key {{info:#{key}}}")
|
19
|
+
@files[key] = file
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(path)
|
23
|
+
key = normalize_path(path)
|
24
|
+
|
25
|
+
if file = @files[key]
|
26
|
+
say_debug("Found file #{file} with path #{path}")
|
27
|
+
return file
|
28
|
+
end
|
29
|
+
|
30
|
+
say_debug("Could {{error:NOT}} find path #{path}")
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def pluck(&block)
|
35
|
+
@files.values.map(&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def normalized_file_path(file)
|
41
|
+
normalize_path(file.absolute_path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_abs(path)
|
45
|
+
File.join(root_path, path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def normalize_path(path)
|
49
|
+
if cached = @paths[path]
|
50
|
+
return cached
|
51
|
+
end
|
52
|
+
|
53
|
+
if Pathname.new(path).absolute?
|
54
|
+
@paths[path] = File.realdirpath(path)
|
55
|
+
else
|
56
|
+
@paths[path] = File.realdirpath(to_abs(path))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/rfix/formatter.rb
CHANGED
@@ -7,26 +7,50 @@ require "shellwords"
|
|
7
7
|
|
8
8
|
module Rfix
|
9
9
|
class Formatter < RuboCop::Formatter::SimpleTextFormatter
|
10
|
+
include Rfix::Log
|
11
|
+
|
10
12
|
def started(files)
|
11
|
-
theme
|
13
|
+
theme = Rouge::Themes::Gruvbox.new
|
12
14
|
@formatter = Rouge::Formatters::TerminalTruecolor.new(theme)
|
13
|
-
@
|
14
|
-
|
15
|
-
|
16
|
-
@
|
17
|
-
@
|
18
|
-
@
|
19
|
-
|
15
|
+
@current = 0
|
16
|
+
@total = files.count
|
17
|
+
@files = {}
|
18
|
+
@lexer = Rouge::Lexers::Ruby.new
|
19
|
+
@pg = CLI::UI::Progress.new
|
20
|
+
@all_files = files
|
21
|
+
end
|
22
|
+
|
23
|
+
def truncate(path)
|
24
|
+
path.sub(::File.join(Dir.getwd, "/"), "")
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_files(files)
|
28
|
+
return unless Rfix.test?
|
29
|
+
|
30
|
+
files.each do |file|
|
31
|
+
offenses = @files.fetch(file)
|
32
|
+
corrected = offenses.select(&:corrected?)
|
33
|
+
|
34
|
+
if offenses.empty?
|
35
|
+
say truncate(file)
|
36
|
+
elsif offenses.count == corrected.count
|
37
|
+
say truncate(file)
|
38
|
+
else
|
39
|
+
say_error truncate(file)
|
40
|
+
end
|
41
|
+
end
|
20
42
|
end
|
21
43
|
|
22
44
|
def finished(files)
|
45
|
+
render_files(files)
|
46
|
+
|
23
47
|
files.each do |file|
|
24
48
|
render_file(file, @files.fetch(file))
|
25
49
|
end
|
26
50
|
|
27
51
|
offenses = @files.values.flatten
|
28
52
|
corrected = offenses.select(&:corrected?)
|
29
|
-
out("\n")
|
53
|
+
out("\n") unless @total.zero?
|
30
54
|
report_summary(files.size, offenses.count, corrected.count)
|
31
55
|
end
|
32
56
|
|
@@ -46,8 +70,11 @@ module Rfix
|
|
46
70
|
end
|
47
71
|
|
48
72
|
def file_finished(file, offenses)
|
73
|
+
out("\n") if @current == 0.0
|
49
74
|
@current += 1.0
|
50
|
-
|
75
|
+
unless Rfix.test?
|
76
|
+
@pg.tick(set_percent: (@current / @total))
|
77
|
+
end
|
51
78
|
@files[file] = offenses
|
52
79
|
end
|
53
80
|
|
data/lib/rfix/git_helper.rb
CHANGED
@@ -4,17 +4,29 @@ require "open3"
|
|
4
4
|
require "rfix"
|
5
5
|
require "rfix/log"
|
6
6
|
require "rfix/cmd"
|
7
|
+
require "shellwords"
|
7
8
|
|
8
9
|
module Rfix::GitHelper
|
9
10
|
include Rfix::Log
|
10
11
|
include Rfix::Cmd
|
11
12
|
|
12
|
-
def git(*
|
13
|
+
def git(*params, root: Dir.pwd, quiet: false, &block)
|
14
|
+
args = split_args(params)
|
13
15
|
args.unshift *["--git-dir", File.join(root, ".git")]
|
14
16
|
args.unshift *["--work-tree", root]
|
15
17
|
cmd("git", *args, quiet: quiet, &block)
|
16
18
|
end
|
17
19
|
|
20
|
+
def split_args(params)
|
21
|
+
return if params.empty?
|
22
|
+
return split(params.first) if params.count == 1
|
23
|
+
return params
|
24
|
+
end
|
25
|
+
|
26
|
+
def split(str)
|
27
|
+
Shellwords.split(str)
|
28
|
+
end
|
29
|
+
|
18
30
|
def has_branch?(branch)
|
19
31
|
cmd_succeeded?("git", "cat-file", "-t", branch)
|
20
32
|
end
|
data/lib/rfix/log.rb
CHANGED
@@ -4,31 +4,128 @@ require "rfix"
|
|
4
4
|
require "cli/ui"
|
5
5
|
|
6
6
|
module Rfix::Log
|
7
|
+
extend self
|
7
8
|
def say(message)
|
8
|
-
|
9
|
+
prt("{{v}} #{message}")
|
9
10
|
end
|
10
11
|
|
11
12
|
def say_error(message)
|
12
|
-
|
13
|
+
prt("{{x}} #{message}")
|
13
14
|
end
|
14
15
|
|
15
16
|
def say_error_sub(message)
|
16
|
-
|
17
|
+
prt(message.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def error_box(title)
|
21
|
+
box(title, color: :red) { yield }
|
22
|
+
end
|
23
|
+
|
24
|
+
def abort_box(title)
|
25
|
+
error_box(title) { yield }
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def say_test(message)
|
30
|
+
prt("{{i}} #{strip(message)}")
|
17
31
|
end
|
18
32
|
|
19
33
|
def say_debug(message)
|
20
|
-
if
|
21
|
-
|
34
|
+
if debug? or test?
|
35
|
+
prt("{{i}} #{strip(message)}", to: $stderr)
|
22
36
|
end
|
23
37
|
end
|
24
38
|
|
25
39
|
def say_abort(message)
|
26
|
-
|
40
|
+
prt("{{x}} #{message}")
|
27
41
|
exit 1
|
28
42
|
end
|
29
43
|
|
44
|
+
def debug?
|
45
|
+
return false unless defined?(RSpec)
|
46
|
+
return RSpec.configuration.debug?
|
47
|
+
end
|
48
|
+
|
49
|
+
def test?
|
50
|
+
Rfix.test?
|
51
|
+
end
|
52
|
+
|
30
53
|
def say_exit(message)
|
31
|
-
|
54
|
+
prt("{{v}} #{message}")
|
32
55
|
exit 0
|
33
56
|
end
|
57
|
+
|
58
|
+
def say_plain(message)
|
59
|
+
prt(message)
|
60
|
+
end
|
61
|
+
|
62
|
+
def debug_box(title)
|
63
|
+
unless_debug do
|
64
|
+
box(title) { yield }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def prt(*args)
|
69
|
+
CLI::UI.puts(*args)
|
70
|
+
end
|
71
|
+
|
72
|
+
def fmt(*args)
|
73
|
+
CLI::UI.fmt(*args)
|
74
|
+
end
|
75
|
+
|
76
|
+
alias ftm fmt
|
77
|
+
|
78
|
+
def log_items(items, title:)
|
79
|
+
box("#{title} (#{items.count})") do
|
80
|
+
return margin(2) do
|
81
|
+
prt "{{warning:No items found}}"
|
82
|
+
end if items.empty?
|
83
|
+
|
84
|
+
items.each do |item|
|
85
|
+
if block_given?
|
86
|
+
say strip(yield item)
|
87
|
+
else
|
88
|
+
say strip(item.to_s)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def box(title, color: :reset)
|
95
|
+
margin do
|
96
|
+
CLI::UI::Frame.open(title, color: color) do
|
97
|
+
margin(2) do
|
98
|
+
yield
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def strip(msg)
|
105
|
+
msg
|
106
|
+
# msg.gsub(current_path, "").gsub(Dir.pwd, ".").chomp
|
107
|
+
end
|
108
|
+
|
109
|
+
def current_path
|
110
|
+
File.join(Dir.pwd, "/")
|
111
|
+
end
|
112
|
+
|
113
|
+
def div(title, **args)
|
114
|
+
CLI::UI::Frame.divider(title, **args)
|
115
|
+
margin { yield }
|
116
|
+
end
|
117
|
+
|
118
|
+
def margin(n = 1)
|
119
|
+
new_line(n)
|
120
|
+
yield
|
121
|
+
new_line(n)
|
122
|
+
end
|
123
|
+
|
124
|
+
def new_line(n = 1)
|
125
|
+
say_plain("\n" * n)
|
126
|
+
end
|
127
|
+
|
128
|
+
def unless_debug
|
129
|
+
yield unless Rfix.debug?
|
130
|
+
end
|
34
131
|
end
|