webtranslateit-safe 0.4.0 → 0.4.1

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +445 -32
  3. data/CHANGELOG +4 -5
  4. data/Gemfile.lock +1 -1
  5. data/bin/webtranslateit-safe +16 -16
  6. data/lib/webtranslateit/safe/archive.rb +4 -9
  7. data/lib/webtranslateit/safe/backup.rb +2 -9
  8. data/lib/webtranslateit/safe/cloudfiles.rb +1 -1
  9. data/lib/webtranslateit/safe/config/builder.rb +6 -16
  10. data/lib/webtranslateit/safe/config/node.rb +14 -21
  11. data/lib/webtranslateit/safe/ftp.rb +26 -26
  12. data/lib/webtranslateit/safe/gpg.rb +2 -8
  13. data/lib/webtranslateit/safe/gzip.rb +1 -5
  14. data/lib/webtranslateit/safe/local.rb +12 -16
  15. data/lib/webtranslateit/safe/mongodump.rb +6 -13
  16. data/lib/webtranslateit/safe/mysqldump.rb +5 -9
  17. data/lib/webtranslateit/safe/pgdump.rb +9 -9
  18. data/lib/webtranslateit/safe/pipe.rb +0 -6
  19. data/lib/webtranslateit/safe/s3.rb +1 -1
  20. data/lib/webtranslateit/safe/sftp.rb +25 -33
  21. data/lib/webtranslateit/safe/sink.rb +4 -9
  22. data/lib/webtranslateit/safe/source.rb +9 -13
  23. data/lib/webtranslateit/safe/stream.rb +6 -14
  24. data/lib/webtranslateit/safe/svndump.rb +1 -5
  25. data/lib/webtranslateit/safe/tmp_file.rb +11 -16
  26. data/lib/webtranslateit/safe/version.rb +1 -5
  27. data/lib/webtranslateit/safe.rb +9 -11
  28. data/spec/webtranslateit/safe/archive_spec.rb +20 -20
  29. data/spec/webtranslateit/safe/cloudfiles_spec.rb +1 -1
  30. data/spec/webtranslateit/safe/config_spec.rb +31 -31
  31. data/spec/webtranslateit/safe/gpg_spec.rb +35 -35
  32. data/spec/webtranslateit/safe/gzip_spec.rb +11 -11
  33. data/spec/webtranslateit/safe/local_spec.rb +27 -27
  34. data/spec/webtranslateit/safe/mongodump_spec.rb +23 -23
  35. data/spec/webtranslateit/safe/mysqldump_spec.rb +30 -30
  36. data/spec/webtranslateit/safe/pgdump_spec.rb +13 -13
  37. data/spec/webtranslateit/safe/s3_spec.rb +1 -1
  38. data/spec/webtranslateit/safe/svndump_spec.rb +9 -9
  39. data/webtranslateit-safe.gemspec +6 -7
  40. metadata +2 -2
data/CHANGELOG CHANGED
@@ -1,9 +1,8 @@
1
- 0.4.0
1
+ 0.4.1
2
2
 
3
- * Rename gem to webtranslateit-safe.
4
- * GitHub Action CI.
5
- * Rubocop Linting.
6
- * Ruby 3.2 compatibility.
3
+ * Add ruby 3.2 compantibility
4
+ * Modernize gem
5
+ * Rename astrails-safe to webtranslateit-safe
7
6
 
8
7
  0.3.1
9
8
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- webtranslateit-safe (0.4.0)
4
+ webtranslateit-safe (0.4.1)
5
5
  aws-s3
6
6
  cloudfiles
7
7
  net-sftp
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'rubygems'
4
4
 
5
- require 'webtranslateit/safe'
5
+ require 'astrails/safe'
6
6
 
7
- include WebTranslateIt::Safe
7
+ include Astrails::Safe
8
8
 
9
9
  def die(msg)
10
10
  puts "ERROR: #{msg}"
@@ -12,16 +12,16 @@ def die(msg)
12
12
  end
13
13
 
14
14
  def usage
15
- puts <<~END
16
- Usage: webtranslateit-safe [OPTIONS] CONFIG_FILE
17
- Options:
18
- -h, --help This help screen
19
- -v, --verbose be verbose, duh!
20
- -n, --dry-run just pretend, don't do anything.
21
- -L, --local skip S3 and Cloud Files
22
-
23
- Note: config file will be created from template if missing
24
- END
15
+ puts <<-END
16
+ Usage: astrails-safe [OPTIONS] CONFIG_FILE
17
+ Options:
18
+ -h, --help This help screen
19
+ -v, --verbose be verbose, duh!
20
+ -n, --dry-run just pretend, don't do anything.
21
+ -L, --local skip S3 and Cloud Files
22
+
23
+ Note: config file will be created from template if missing
24
+ END
25
25
  exit 1
26
26
  end
27
27
 
@@ -30,7 +30,7 @@ OPTS = [
30
30
  '-v', '--verbose', '--not-verbose',
31
31
  '-n', '--dry-run', '--not-dry-run',
32
32
  '-L', '--local', '--not-local'
33
- ].freeze
33
+ ]
34
34
  def main
35
35
  opts = ARGV & OPTS
36
36
  args = ARGV - OPTS
@@ -40,14 +40,14 @@ def main
40
40
 
41
41
  config_file = File.expand_path(args.first)
42
42
 
43
- is_dry = (opts.delete('-n') || opts.delete('--dry-run')) && !opts.delete('--not-dry-run')
43
+ is_dry = (opts.delete('-n') || opts.delete('--dry-run')) && ! opts.delete('--not-dry-run')
44
44
  is_verbose = (opts.delete('-v') || opts.delete('--verbose')) && !opts.delete('--not-verbose')
45
45
  is_local_only = (opts.delete('-L') || opts.delete('--local')) && !opts.delete('--not-local')
46
46
 
47
47
  unless File.exist?(config_file)
48
48
  die 'Missing configuration file. NOT CREATED! Rerun w/o the -n argument to create a template configuration file.' if is_dry
49
49
 
50
- FileUtils.cp File.join(WebTranslateIt::Safe::ROOT, 'templates', 'script.rb'), config_file
50
+ FileUtils.cp File.join(Astrails::Safe::ROOT, 'templates', 'script.rb'), config_file
51
51
 
52
52
  die "Created default #{config_file}. Please edit and run again."
53
53
  end
@@ -61,4 +61,4 @@ def main
61
61
  process config
62
62
  end
63
63
 
64
- main
64
+ main
@@ -1,29 +1,24 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Archive < Source
6
4
 
7
5
  def command
8
6
  "tar -cf - #{config[:options]} #{tar_exclude_files} #{tar_files}"
9
7
  end
10
8
 
11
- def extension = '.tar'
9
+ def extension; '.tar'; end
12
10
 
13
11
  protected
14
12
 
15
13
  def tar_exclude_files
16
- [*config[:exclude]].compact.map { |x| "--exclude=#{x}" }.join(' ')
14
+ [*config[:exclude]].compact.map{|x| "--exclude=#{x}"}.join(' ')
17
15
  end
18
16
 
19
17
  def tar_files
20
- raise 'missing files for tar' unless config[:files]
21
-
22
- [*config[:files]].map(&:strip).join(' ')
18
+ raise RuntimeError, 'missing files for tar' unless config[:files]
19
+ [*config[:files]].map{|s| s.strip}.join(' ')
23
20
  end
24
21
 
25
22
  end
26
-
27
23
  end
28
-
29
24
  end
@@ -1,14 +1,10 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Backup
6
-
7
4
  attr_accessor :id, :kind, :filename, :extension, :command, :compressed, :timestamp, :path
8
-
9
5
  def initialize(opts = {})
10
6
  opts.each do |k, v|
11
- send("#{k}=", v)
7
+ self.send("#{k}=", v)
12
8
  end
13
9
  end
14
10
 
@@ -19,9 +15,6 @@ module WebTranslateIt
19
15
  WebTranslateIt::Safe.const_get(mod).new(config, self).process
20
16
  end
21
17
  end
22
-
23
18
  end
24
-
25
19
  end
26
-
27
- end
20
+ end
@@ -74,4 +74,4 @@ module WebTranslateIt
74
74
  end
75
75
  end
76
76
  end
77
- end
77
+ end
@@ -1,19 +1,15 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  module Config
6
-
7
4
  class Builder
8
5
 
9
6
  def initialize(node, data = {})
10
7
  @node = node
11
- data.each { |k, v| send k, v }
8
+ data.each { |k, v| self.send k, v }
12
9
  end
13
10
 
14
11
 
15
12
  class << self
16
-
17
13
  def simple_value(*names)
18
14
  names.each do |m|
19
15
  define_method(m) do |value|
@@ -44,7 +40,7 @@ module WebTranslateIt
44
40
 
45
41
  def mixed_value(*names)
46
42
  names.each do |m|
47
- define_method(m) do |data = {}, &block|
43
+ define_method(m) do |data={}, &block|
48
44
  ensure_uniq(m)
49
45
  if data.is_a?(Hash) || block
50
46
  ensure_hash(m, data) if block
@@ -58,9 +54,8 @@ module WebTranslateIt
58
54
 
59
55
  def collection(*names)
60
56
  names.each do |m|
61
- define_method(m) do |id, data = {}, &block|
57
+ define_method(m) do |id, data={}, &block|
62
58
  raise "bad collection id: #{id.inspect}" unless id
63
-
64
59
  ensure_hash(m, data)
65
60
 
66
61
  name = "#{m}s"
@@ -69,15 +64,14 @@ module WebTranslateIt
69
64
  end
70
65
  end
71
66
  end
72
-
73
67
  end
74
68
 
75
69
  simple_value :verbose, :dry_run, :local_only, :path, :command,
76
- :options, :user, :host, :port, :password, :key, :secret, :bucket,
77
- :api_key, :container, :socket, :service_net, :repo_path
70
+ :options, :user, :host, :port, :password, :key, :secret, :bucket,
71
+ :api_key, :container, :socket, :service_net, :repo_path
78
72
  multi_value :skip_tables, :exclude, :files
79
73
  hash_value :mysqldump, :tar, :gpg, :keep, :pgdump, :tar, :svndump,
80
- :sftp, :ftp, :mongodump
74
+ :sftp, :ftp, :mongodump
81
75
  mixed_value :s3, :local, :cloudfiles
82
76
  collection :database, :archive, :repo
83
77
 
@@ -90,11 +84,7 @@ module WebTranslateIt
90
84
  def ensure_hash(k, v)
91
85
  raise "#{k}: hash expected: #{v.inspect}" unless v.is_a?(Hash)
92
86
  end
93
-
94
87
  end
95
-
96
88
  end
97
-
98
89
  end
99
-
100
90
  end
@@ -1,21 +1,17 @@
1
1
  require 'webtranslateit/safe/config/builder'
2
2
  module WebTranslateIt
3
-
4
3
  module Safe
5
-
6
4
  module Config
7
-
8
5
  class Node
9
-
10
6
  attr_reader :parent, :data
11
7
 
12
- def initialize(parent = nil, data = {}, &)
8
+ def initialize(parent = nil, data = {}, &block)
13
9
  @parent = parent
14
10
  @data = {}
15
- merge(data, &)
11
+ merge data, &block
16
12
  end
17
13
 
18
- def merge(data = {}, &block)
14
+ def merge data = {}, &block
19
15
  builder = Builder.new(self, data)
20
16
  builder.instance_eval(&block) if block
21
17
  self
@@ -25,37 +21,38 @@ module WebTranslateIt
25
21
  def get(*path)
26
22
  key = path.shift
27
23
  value = @data[key.to_s]
28
- return value if !value.nil? && path.empty?
24
+ return value if (nil != value) && path.empty?
29
25
 
30
- value&.get(*path)
26
+ value && value.get(*path)
31
27
  end
32
28
 
33
29
  # recursive find
34
30
  # starts at the node and continues to the parent
35
31
  def find(*path)
36
- get(*path) || @parent&.find(*path)
32
+ get(*path) || @parent && @parent.find(*path)
37
33
  end
38
- alias [] find
34
+ alias :[] :find
39
35
 
40
36
  def set_multi(key, value)
41
37
  @data[key.to_s] ||= []
42
- @data[key.to_s].push(*value)
38
+ @data[key.to_s].concat [*value]
43
39
  end
44
40
 
45
41
  def set(key, value)
46
42
  @data[key.to_s] = value
47
43
  end
48
- alias []= set
44
+ alias :[]= :set
49
45
 
50
- def each(&)
51
- @data.each(&)
46
+ def each(&block)
47
+ @data.each(&block)
52
48
  end
53
49
  include Enumerable
54
50
 
55
51
  def to_hash
56
- @data.keys.each_with_object({}) do |key, res|
52
+ @data.keys.inject({}) do |res, key|
57
53
  value = @data[key]
58
54
  res[key] = value.is_a?(Node) ? value.to_hash : value
55
+ res
59
56
  end
60
57
  end
61
58
 
@@ -63,17 +60,13 @@ module WebTranslateIt
63
60
  @data.each do |key, value|
64
61
  if value.is_a?(Node)
65
62
  puts "#{indent}#{key}:"
66
- value.dump("#{indent} ")
63
+ value.dump(indent + ' ')
67
64
  else
68
65
  puts "#{indent}#{key}: #{value.inspect}"
69
66
  end
70
67
  end
71
68
  end
72
-
73
69
  end
74
-
75
70
  end
76
-
77
71
  end
78
-
79
72
  end
@@ -1,7 +1,5 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Ftp < Sink
6
4
 
7
5
  protected
@@ -15,44 +13,48 @@ module WebTranslateIt
15
13
  end
16
14
 
17
15
  def save
18
- raise 'pipe-streaming not supported for FTP.' unless @backup.path
16
+ raise RuntimeError, 'pipe-streaming not supported for FTP.' unless @backup.path
19
17
 
20
18
  puts "Uploading #{host}:#{full_path} via FTP" if verbose? || dry_run?
21
19
 
22
- return if dry_run? || local_only?
23
-
24
- port ||= 21
25
- Net::FTP.open(host) do |ftp|
26
- ftp.connect(host, port)
27
- ftp.login(user, password)
28
- puts "Sending #{@backup.path} to #{full_path}" if verbose?
29
- begin
30
- ftp.put(@backup.path, full_path)
31
- rescue Net::FTPPermError
32
- puts "Ensuring remote path (#{path}) exists" if verbose?
20
+ unless dry_run? || local_only?
21
+ if !port
22
+ port = 21
23
+ end
24
+ Net::FTP.open(host) do |ftp|
25
+ ftp.connect(host, port)
26
+ ftp.login(user, password)
27
+ puts "Sending #{@backup.path} to #{full_path}" if verbose?
28
+ begin
29
+ ftp.put(@backup.path, full_path)
30
+ rescue Net::FTPPermError
31
+ puts "Ensuring remote path (#{path}) exists" if verbose?
32
+ end
33
33
  end
34
+ puts '...done' if verbose?
34
35
  end
35
- puts '...done' if verbose?
36
36
  end
37
37
 
38
38
  def cleanup
39
39
  return if local_only? || dry_run?
40
40
 
41
- return unless (keep = config[:keep, :ftp])
41
+ return unless keep = config[:keep, :ftp]
42
42
 
43
43
  puts "listing files: #{host}:#{base}*" if verbose?
44
- port ||= 21
44
+ if !port
45
+ port = 21
46
+ end
45
47
  Net::FTP.open(host) do |ftp|
46
48
  ftp.connect(host, port)
47
49
  ftp.login(user, password)
48
50
  files = ftp.nlst(path)
49
- pattern = File.basename(base.to_s)
50
- files = files.select { |x| x.start_with?(pattern) }
51
- puts(files.collect { |x| x }) if verbose?
51
+ pattern = File.basename("#{base}")
52
+ files = files.reject{ |x| !x.start_with?(pattern)}
53
+ puts files.collect {|x| x} if verbose?
52
54
 
53
- files = files
54
- .collect { |x| x }
55
- .sort
55
+ files = files.
56
+ collect {|x| x }.
57
+ sort
56
58
 
57
59
  cleanup_with_limit(files, keep) do |f|
58
60
  file = File.join(path, f)
@@ -79,7 +81,5 @@ module WebTranslateIt
79
81
  end
80
82
 
81
83
  end
82
-
83
84
  end
84
-
85
- end
85
+ end
@@ -1,11 +1,9 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Gpg < Pipe
6
4
 
7
5
  def active?
8
- raise "can't use both gpg password and pubkey" if key && password
6
+ raise RuntimeError, "can't use both gpg password and pubkey" if key && password
9
7
 
10
8
  !!(password || key)
11
9
  end
@@ -41,12 +39,8 @@ module WebTranslateIt
41
39
 
42
40
  def gpg_password_file(pass)
43
41
  return 'TEMP_GENERATED_FILENAME' if dry_run?
44
-
45
42
  WebTranslateIt::Safe::TmpFile.create('gpg-pass') { |file| file.write(pass) }
46
43
  end
47
-
48
44
  end
49
-
50
45
  end
51
-
52
- end
46
+ end
@@ -1,7 +1,5 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Gzip < Pipe
6
4
 
7
5
  protected
@@ -23,7 +21,5 @@ module WebTranslateIt
23
21
  end
24
22
 
25
23
  end
26
-
27
24
  end
28
-
29
- end
25
+ end
@@ -1,7 +1,5 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Local < Sink
6
4
 
7
5
  def active?
@@ -13,7 +11,7 @@ module WebTranslateIt
13
11
  protected
14
12
 
15
13
  def path
16
- @path ||= File.expand_path(expand(config[:local, :path] || raise('missing :local/:path')))
14
+ @path ||= File.expand_path(expand(config[:local, :path] || raise(RuntimeError, 'missing :local/:path')))
17
15
  end
18
16
 
19
17
  def save
@@ -22,34 +20,32 @@ module WebTranslateIt
22
20
  # FIXME: probably need to change this to smth like @backup.finalize!
23
21
  @backup.path = full_path # need to do it outside DRY_RUN so that it will be avialable for S3 DRY_RUN
24
22
 
25
- return if dry_run?
26
-
27
- FileUtils.mkdir_p(path) unless File.directory?(path)
28
- benchmark = Benchmark.realtime do
29
- system "#{@backup.command}>#{@backup.path}"
23
+ unless dry_run?
24
+ FileUtils.mkdir_p(path) unless File.directory?(path)
25
+ benchmark = Benchmark.realtime do
26
+ system "#{@backup.command}>#{@backup.path}"
27
+ end
28
+ puts('command took ' + sprintf('%.2f', benchmark) + ' second(s).') if verbose?
30
29
  end
31
- puts("command took #{format('%.2f', benchmark)} second(s).") if verbose?
30
+
32
31
  end
33
32
 
34
33
  def cleanup
35
- return unless (keep = config[:keep, :local])
34
+ return unless keep = config[:keep, :local]
36
35
 
37
36
  puts "listing files #{base}" if verbose?
38
37
 
39
38
  # TODO: cleanup ALL zero-length files
40
39
 
41
- files = Dir["#{base}*"]
42
- .select { |f| File.file?(f) && File.size(f).positive? }
43
- .sort
40
+ files = Dir["#{base}*"] .
41
+ select{|f| File.file?(f) && File.size(f) > 0} .
42
+ sort
44
43
 
45
44
  cleanup_with_limit(files, keep) do |f|
46
45
  puts "removing local file #{f}" if dry_run? || verbose?
47
46
  File.unlink(f) unless dry_run?
48
47
  end
49
48
  end
50
-
51
49
  end
52
-
53
50
  end
54
-
55
51
  end
@@ -1,30 +1,23 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Mongodump < Source
6
-
7
-
4
+
8
5
  def command
9
6
  opts = []
10
7
  opts << "--host #{config[:host]}" if config[:host]
11
8
  opts << "-u #{config[:user]}" if config[:user]
12
9
  opts << "-p #{config[:password]}" if config[:password]
13
10
  opts << "--out #{output_directory}"
14
-
15
- "mongodump -q \"{xxxx : { \\$ne : 0 } }\" --db #{@id} #{opts.join(' ')} && cd #{output_directory} && tar cf - ."
11
+
12
+ "mongodump -q \"{xxxx : { \\$ne : 0 } }\" --db #{@id} #{opts.join(" ")} && cd #{output_directory} && tar cf - ."
16
13
  end
17
-
18
- def extension = '.tar'
19
-
14
+
15
+ def extension; '.tar'; end
16
+
20
17
  protected
21
-
22
18
  def output_directory
23
19
  File.join(TmpFile.tmproot, 'mongodump')
24
20
  end
25
-
26
21
  end
27
-
28
22
  end
29
-
30
23
  end
@@ -1,14 +1,12 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Mysqldump < Source
6
4
 
7
5
  def command
8
6
  "mysqldump --defaults-extra-file=#{mysql_password_file} #{config[:options]} #{mysql_skip_tables} #{@id}"
9
7
  end
10
8
 
11
- def extension = '.sql'
9
+ def extension; '.sql'; end
12
10
 
13
11
  protected
14
12
 
@@ -24,13 +22,11 @@ module WebTranslateIt
24
22
  end
25
23
 
26
24
  def mysql_skip_tables
27
- return unless (skip_tables = config[:skip_tables])
28
-
29
- [*skip_tables].map { |t| "--ignore-table=#{@id}.#{t}" }.join(' ')
25
+ if skip_tables = config[:skip_tables]
26
+ [*skip_tables].map{ |t| "--ignore-table=#{@id}.#{t}" }.join(' ')
27
+ end
30
28
  end
31
29
 
32
30
  end
33
-
34
31
  end
35
-
36
- end
32
+ end
@@ -1,15 +1,17 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Pgdump < Source
6
4
 
7
5
  def command
8
- ENV['PGPASSWORD'] = (config['password'] || nil)
6
+ if config['password']
7
+ ENV['PGPASSWORD'] = config['password']
8
+ else
9
+ ENV['PGPASSWORD'] = nil
10
+ end
9
11
  "pg_dump #{postgres_options} #{postgres_username} #{postgres_host} #{postgres_port} #{@id}"
10
12
  end
11
13
 
12
- def extension = '.sql'
14
+ def extension; '.sql'; end
13
15
 
14
16
  protected
15
17
 
@@ -18,19 +20,17 @@ module WebTranslateIt
18
20
  end
19
21
 
20
22
  def postgres_host
21
- config['host'] && "--host='#{config['host']}'"
23
+ config['host'] && "--host='#{config["host"]}'"
22
24
  end
23
25
 
24
26
  def postgres_port
25
- config['port'] && "--port='#{config['port']}'"
27
+ config['port'] && "--port='#{config["port"]}'"
26
28
  end
27
29
 
28
30
  def postgres_username
29
- config['user'] && "--username='#{config['user']}'"
31
+ config['user'] && "--username='#{config["user"]}'"
30
32
  end
31
33
 
32
34
  end
33
-
34
35
  end
35
-
36
36
  end
@@ -1,9 +1,6 @@
1
1
  module WebTranslateIt
2
-
3
2
  module Safe
4
-
5
3
  class Pipe < Stream
6
-
7
4
  # process adds required commands to the current
8
5
  # shell command string
9
6
  # :active?, :pipe, :extension and :post_process are
@@ -15,9 +12,6 @@ module WebTranslateIt
15
12
  @backup.extension << extension
16
13
  post_process
17
14
  end
18
-
19
15
  end
20
-
21
16
  end
22
-
23
17
  end
@@ -77,4 +77,4 @@ module WebTranslateIt
77
77
  end
78
78
  end
79
79
  end
80
- end
80
+ end