toys 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -97,11 +97,11 @@ module Toys
97
97
  # Create a standard CLI, configured with the appropriate paths and
98
98
  # middleware.
99
99
  #
100
- # @param [String,nil] directory Starting search directory for configs.
100
+ # @param [String,nil] cur_dir Starting search directory for configs.
101
101
  # Defaults to the current working directory.
102
102
  # @return [Toys::CLI]
103
103
  #
104
- def self.create(directory: nil)
104
+ def self.create(cur_dir: nil)
105
105
  cli = CLI.new(
106
106
  binary_name: BINARY_NAME,
107
107
  config_dir_name: CONFIG_DIR_NAME,
@@ -111,7 +111,7 @@ module Toys
111
111
  middleware_stack: default_middleware_stack,
112
112
  template_lookup: default_template_lookup
113
113
  )
114
- add_standard_paths(cli, directory: directory)
114
+ add_standard_paths(cli, cur_dir: cur_dir)
115
115
  cli
116
116
  end
117
117
 
@@ -127,17 +127,16 @@ module Toys
127
127
  # * The builtins for the standard toys binary.
128
128
  #
129
129
  # @param [Toys::CLI] cli Add paths to this CLI
130
- # @param [String,nil] directory Starting search directory for configs.
130
+ # @param [String,nil] cur_dir Starting search directory for configs.
131
131
  # Defaults to the current working directory.
132
- #
133
- def self.add_standard_paths(cli, directory: nil)
134
- cli.add_search_path_hierarchy(start: directory)
135
- paths = ::ENV["TOYS_PATH"].to_s.split(::File::PATH_SEPARATOR)
136
- if paths.empty?
137
- paths << ::ENV["HOME"] if ::ENV["HOME"]
138
- paths << "/etc" if ::File.directory?("/etc") && ::File.readable?("/etc")
139
- end
140
- paths.each { |path| cli.add_search_path(path) }
132
+ # @param [Array<String>,nil] global_dirs Optional list of global
133
+ # directories, or `nil` to use the defaults.
134
+ #
135
+ def self.add_standard_paths(cli, cur_dir: nil, global_dirs: nil)
136
+ cur_dir ||= ::Dir.pwd
137
+ global_dirs ||= default_global_dirs
138
+ cli.add_search_path_hierarchy(start: cur_dir, terminate: global_dirs)
139
+ global_dirs.each { |path| cli.add_search_path(path) }
141
140
  cli.add_config_path(BUILTINS_PATH)
142
141
  cli
143
142
  end
@@ -145,7 +144,7 @@ module Toys
145
144
  # rubocop:disable Metrics/MethodLength
146
145
 
147
146
  ##
148
- # Returns a the middleware for the standard Toys CLI.
147
+ # Returns the middleware for the standard Toys CLI.
149
148
  #
150
149
  # @return [Array]
151
150
  #
@@ -192,6 +191,25 @@ module Toys
192
191
 
193
192
  # rubocop:enable Metrics/MethodLength
194
193
 
194
+ ##
195
+ # Returns the default set of global config directories.
196
+ #
197
+ # @return [Array<String>]
198
+ #
199
+ def self.default_global_dirs
200
+ paths = ::ENV["TOYS_PATH"].to_s.split(::File::PATH_SEPARATOR)
201
+ if paths.empty?
202
+ paths << ::ENV["HOME"] if ::ENV["HOME"]
203
+ paths << "/etc" if ::File.directory?("/etc") && ::File.readable?("/etc")
204
+ end
205
+ paths.map { |path| ::File.realpath(::File.expand_path(path)) }
206
+ end
207
+
208
+ ##
209
+ # Returns a ModuleLookup for the default templates.
210
+ #
211
+ # @return [Toys::Utils::ModuleLookup]
212
+ #
195
213
  def self.default_template_lookup
196
214
  Utils::ModuleLookup.new.add_path("toys/templates")
197
215
  end
@@ -73,7 +73,7 @@ module Toys
73
73
 
74
74
  files.each do |file|
75
75
  if ::File.exist?(file)
76
- rm_rf file
76
+ rm_rf(file)
77
77
  puts "Cleaned: #{file}"
78
78
  end
79
79
  end
@@ -27,8 +27,6 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
- require "rubygems/package"
31
-
32
30
  module Toys
33
31
  module Templates
34
32
  ##
@@ -95,25 +93,26 @@ module Toys
95
93
  include :terminal
96
94
 
97
95
  run do
96
+ require "rubygems/package"
98
97
  configure_exec(exit_on_nonzero_status: true)
99
- gemspec = ::Gem::Specification.load "#{template.gem_name}.gemspec"
98
+ gemspec = ::Gem::Specification.load("#{template.gem_name}.gemspec")
100
99
  version = gemspec.version
101
100
  gemfile = "#{template.gem_name}-#{version}.gem"
102
- ::Gem::Package.build gemspec
103
- mkdir_p "pkg"
104
- mv gemfile, "pkg"
101
+ ::Gem::Package.build(gemspec)
102
+ mkdir_p("pkg")
103
+ mv(gemfile, "pkg")
105
104
  if template.push_gem
106
105
  if ::File.directory?(".git") && capture("git status -s").strip != ""
107
106
  logger.error "Cannot push the gem when there are uncommited changes"
108
107
  exit(1)
109
108
  end
110
109
  exit(1) unless option(:yes) || confirm("Release #{gemfile}?")
111
- sh "gem push pkg/#{gemfile}"
110
+ exec(["gem", "push", "pkg/#{gemfile}"])
112
111
  if template.tag
113
- sh "git tag v#{version}"
112
+ exec(["git", "tag", "v#{version}"])
114
113
  if template.push_tag
115
114
  template.push_tag = "origin" if template.push_tag == true
116
- sh "git push #{template.push_tag} v#{version}"
115
+ exec(["git", "push", template.push_tag, "v#{version}"])
117
116
  end
118
117
  end
119
118
  end
@@ -35,6 +35,12 @@ module Toys
35
35
  class Minitest
36
36
  include Template
37
37
 
38
+ ##
39
+ # Default version requirements for the minitest gem.
40
+ # @return [Array<String>]
41
+ #
42
+ DEFAULT_GEM_VERSION_REQUIREMENTS = "~> 5.0".freeze
43
+
38
44
  ##
39
45
  # Default tool name
40
46
  # @return [String]
@@ -58,6 +64,8 @@ module Toys
58
64
  #
59
65
  # @param [String] name Name of the tool to create. Defaults to
60
66
  # {DEFAULT_TOOL_NAME}.
67
+ # @param [String,Array<String>] gem_version Version requirements for
68
+ # the minitest gem. Defaults to {DEFAULT_GEM_VERSION_REQUIREMENTS}.
61
69
  # @param [Array<String>] libs An array of library paths to add to the
62
70
  # ruby require path. Defaults to {DEFAULT_LIBS}.
63
71
  # @param [Array<String>] files An array of globs indicating the test
@@ -65,17 +73,20 @@ module Toys
65
73
  # @param [Boolean] warnings If true, runs tests with Ruby warnings.
66
74
  # Defaults to true.
67
75
  #
68
- def initialize(name: DEFAULT_TOOL_NAME,
69
- libs: DEFAULT_LIBS,
70
- files: DEFAULT_FILES,
76
+ def initialize(name: nil,
77
+ gem_version: nil,
78
+ libs: nil,
79
+ files: nil,
71
80
  warnings: true)
72
- @name = name
73
- @libs = libs
74
- @files = files
81
+ @name = name || DEFAULT_TOOL_NAME
82
+ @gem_version = gem_version || DEFAULT_GEM_VERSION_REQUIREMENTS
83
+ @libs = libs || DEFAULT_LIBS
84
+ @files = files || DEFAULT_FILES
75
85
  @warnings = warnings
76
86
  end
77
87
 
78
88
  attr_accessor :name
89
+ attr_accessor :gem_version
79
90
  attr_accessor :libs
80
91
  attr_accessor :files
81
92
  attr_accessor :warnings
@@ -93,6 +104,7 @@ module Toys
93
104
  remaining_args :tests, desc: "Paths to the tests to run (defaults to all tests)"
94
105
 
95
106
  run do
107
+ gem("minitest", *Array(template.gem_version))
96
108
  ruby_args = []
97
109
  unless template.libs.empty?
98
110
  lib_path = template.libs.join(::File::PATH_SEPARATOR)
@@ -0,0 +1,145 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ module Toys
31
+ module Templates
32
+ ##
33
+ # A template that generates rdoc tools.
34
+ #
35
+ class Rdoc
36
+ include Template
37
+
38
+ ##
39
+ # Default version requirements for the rdoc gem.
40
+ # @return [Array<String>]
41
+ #
42
+ DEFAULT_GEM_VERSION_REQUIREMENTS = ">= 5.0.0".freeze
43
+
44
+ ##
45
+ # Default tool name
46
+ # @return [String]
47
+ #
48
+ DEFAULT_TOOL_NAME = "rdoc".freeze
49
+
50
+ ##
51
+ # Default output directory
52
+ # @return [String]
53
+ #
54
+ DEFAULT_OUTPUT_DIR = "html".freeze
55
+
56
+ ##
57
+ # Create the template settings for the Rdoc template.
58
+ #
59
+ # @param [String] name Name of the tool to create. Defaults to
60
+ # {DEFAULT_TOOL_NAME}.
61
+ # @param [String,Array<String>] gem_version Version requirements for
62
+ # the rdoc gem. Defaults to {DEFAULT_GEM_VERSION_REQUIREMENTS}.
63
+ # @param [Array<String>] files An array of globs indicating the files
64
+ # to document.
65
+ # @param [String] output_dir Name of directory to receive html output
66
+ # files. Defaults to {DEFAULT_OUTPUT_DIR}.
67
+ # @param [String,nil] markup Markup format. Allowed values include
68
+ # "rdoc", "rd", and "tomdoc". Default is "rdoc".
69
+ # @param [String,nil] title Title of RDoc documentation. If `nil`, RDoc
70
+ # will use a default title.
71
+ # @param [String,nil] main Name of the file to use as the main top level
72
+ # document. Default is none.
73
+ # @param [String,nil] template Name of the template to use. If `nil`,
74
+ # RDoc will use its default template.
75
+ # @param [String,nil] generator Name of the format generator. If `nil`,
76
+ # RDoc will use its default generator.
77
+ # @param [Array<String>] options Additional options to pass to RDoc.
78
+ #
79
+ def initialize(name: nil,
80
+ gem_version: nil,
81
+ files: [],
82
+ output_dir: nil,
83
+ markup: nil,
84
+ title: nil,
85
+ main: nil,
86
+ template: nil,
87
+ generator: nil,
88
+ options: [])
89
+ @name = name || DEFAULT_TOOL_NAME
90
+ @gem_version = gem_version || DEFAULT_GEM_VERSION_REQUIREMENTS
91
+ @files = files
92
+ @output_dir = output_dir || DEFAULT_OUTPUT_DIR
93
+ @markup = markup
94
+ @title = title
95
+ @main = main
96
+ @template = template
97
+ @generator = generator
98
+ @options = options
99
+ end
100
+
101
+ attr_accessor :name
102
+ attr_accessor :gem_version
103
+ attr_accessor :files
104
+ attr_accessor :output_dir
105
+ attr_accessor :markup
106
+ attr_accessor :title
107
+ attr_accessor :main
108
+ attr_accessor :template
109
+ attr_accessor :generator
110
+ attr_accessor :options
111
+
112
+ to_expand do |template|
113
+ tool(template.name) do
114
+ desc "Run rdoc on the current project."
115
+
116
+ include :exec
117
+
118
+ run do
119
+ gem("rdoc", *Array(template.gem_version))
120
+ require "rdoc"
121
+
122
+ files = []
123
+ patterns = Array(template.files)
124
+ patterns = ["lib/**/*.rb"] if patterns.empty?
125
+ patterns.each do |pattern|
126
+ files.concat(::Dir.glob(pattern))
127
+ end
128
+ files.uniq!
129
+
130
+ args = template.options.dup
131
+ args << "-o" << template.output_dir
132
+ args << "--markup" << template.markup if template.markup
133
+ args << "--main" << template.main if template.main
134
+ args << "--title" << template.title if template.title
135
+ args << "-T" << template.template if template.template
136
+ args << "-f" << template.generator if template.generator
137
+
138
+ exec_proc(proc { RDoc::RDoc.new.document(args + files) },
139
+ exit_on_nonzero_status: true)
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -35,6 +35,12 @@ module Toys
35
35
  class Rubocop
36
36
  include Template
37
37
 
38
+ ##
39
+ # Default version requirements for the rubocop gem.
40
+ # @return [Array<String>]
41
+ #
42
+ DEFAULT_GEM_VERSION_REQUIREMENTS = [].freeze
43
+
38
44
  ##
39
45
  # Default tool name
40
46
  # @return [String]
@@ -46,20 +52,25 @@ module Toys
46
52
  #
47
53
  # @param [String] name Name of the tool to create. Defaults to
48
54
  # {DEFAULT_TOOL_NAME}.
55
+ # @param [String,Array<String>] gem_version Version requirements for
56
+ # the rubocop gem. Defaults to {DEFAULT_GEM_VERSION_REQUIREMENTS}.
49
57
  # @param [Boolean] fail_on_error If true, exits with a nonzero code if
50
58
  # Rubocop fails. Defaults to true.
51
59
  # @param [Array<String>] options Additional options passed to the Rubocop
52
60
  # CLI.
53
61
  #
54
62
  def initialize(name: DEFAULT_TOOL_NAME,
63
+ gem_version: nil,
55
64
  fail_on_error: true,
56
65
  options: [])
57
66
  @name = name
67
+ @gem_version = gem_version || DEFAULT_GEM_VERSION_REQUIREMENTS
58
68
  @fail_on_error = fail_on_error
59
69
  @options = options
60
70
  end
61
71
 
62
72
  attr_accessor :name
73
+ attr_accessor :gem_version
63
74
  attr_accessor :fail_on_error
64
75
  attr_accessor :options
65
76
 
@@ -67,10 +78,10 @@ module Toys
67
78
  tool(template.name) do
68
79
  desc "Run rubocop on the current project."
69
80
 
70
- include :exec
71
-
72
81
  run do
82
+ gem("rubocop", *Array(template.gem_version))
73
83
  require "rubocop"
84
+
74
85
  cli = ::RuboCop::CLI.new
75
86
  logger.info "Running RuboCop..."
76
87
  result = cli.run(template.options)
@@ -30,11 +30,17 @@
30
30
  module Toys
31
31
  module Templates
32
32
  ##
33
- # A template for tools that run yardoc
33
+ # A template that generates yardoc tools.
34
34
  #
35
35
  class Yardoc
36
36
  include Template
37
37
 
38
+ ##
39
+ # Default version requirements for the yard gem.
40
+ # @return [String]
41
+ #
42
+ DEFAULT_GEM_VERSION_REQUIREMENTS = "~> 0.9".freeze
43
+
38
44
  ##
39
45
  # Default tool name
40
46
  # @return [String]
@@ -46,24 +52,98 @@ module Toys
46
52
  #
47
53
  # @param [String] name Name of the tool to create. Defaults to
48
54
  # {DEFAULT_TOOL_NAME}.
55
+ # @param [String,Array<String>] gem_version Version requirements for
56
+ # the yard gem. Defaults to {DEFAULT_GEM_VERSION_REQUIREMENTS}.
49
57
  # @param [Array<String>] files An array of globs indicating the files
50
58
  # to document.
59
+ # @param [Boolean] generate_output Whether to generate output. Setting to
60
+ # false causes yardoc to emit warnings/errors but not generate html.
61
+ # Defaults to true.
62
+ # @param [Boolean] generate_output_flag Whether to create a flag
63
+ # `--[no-]output` that can control whether output is generated.
64
+ # Defaults to false.
65
+ # @param [String,nil] output_dir Output directory. Defaults to "doc".
66
+ # @param [Boolean] fail_on_warning Whether the tool should return a
67
+ # nonzero error code if any warnings happen. Defaults to false.
68
+ # @param [Boolean] fail_on_undocumented_objects Whether the tool should
69
+ # return a nonzero error code if any objects remain undocumented.
70
+ # Defaults to false.
71
+ # @param [Boolean] show_public Show public methods. Defaults to true.
72
+ # @param [Boolean] show_protected Show protected methods. Defaults to
73
+ # false.
74
+ # @param [Boolean] show_private Show private methods. Defaults to false.
75
+ # @param [Boolean] hide_private_tag Hide methods with the `@private` tag.
76
+ # Defaults to false.
77
+ # @param [String,nil] readme Name of the readme file used as the title
78
+ # page, or `nil` to use the default.
79
+ # @param [String,nil] markup Markup style used in documentation. Defaults
80
+ # to "rdoc".
81
+ # @param [String,nil] template Template to use. Defaults to "default".
82
+ # @param [String,nil] template_path The optional template path to look
83
+ # for templates in.
84
+ # @param [String,nil] format The output format for the template. Defaults
85
+ # to "html".
51
86
  # @param [Array<String>] options Additional options passed to YARD
52
87
  # @param [Array<String>] stats_options Additional options passed to YARD
53
88
  # stats
54
89
  #
55
- def initialize(name: DEFAULT_TOOL_NAME,
90
+ def initialize(name: nil,
91
+ gem_version: nil,
56
92
  files: [],
93
+ generate_output: true,
94
+ generate_output_flag: false,
95
+ output_dir: nil,
96
+ fail_on_warning: false,
97
+ fail_on_undocumented_objects: false,
98
+ show_public: true,
99
+ show_protected: false,
100
+ show_private: false,
101
+ hide_private_tag: false,
102
+ readme: nil,
103
+ markup: nil,
104
+ template: nil,
105
+ template_path: nil,
106
+ format: nil,
57
107
  options: [],
58
108
  stats_options: [])
59
- @name = name
109
+ @name = name || DEFAULT_TOOL_NAME
110
+ @gem_version = gem_version || DEFAULT_GEM_VERSION_REQUIREMENTS
60
111
  @files = files
112
+ @generate_output = generate_output
113
+ @generate_output_flag = generate_output_flag
114
+ @output_dir = output_dir
115
+ @fail_on_warning = fail_on_warning
116
+ @fail_on_undocumented_objects = fail_on_undocumented_objects
117
+ @show_public = show_public
118
+ @show_protected = show_protected
119
+ @show_private = show_private
120
+ @hide_private_tag = hide_private_tag
121
+ @readme = readme
122
+ @markup = markup
123
+ @template = template
124
+ @template_path = template_path
125
+ @format = format
61
126
  @options = options
62
127
  @stats_options = stats_options
63
128
  end
64
129
 
65
130
  attr_accessor :name
131
+ attr_accessor :gem_version
66
132
  attr_accessor :files
133
+ attr_accessor :generate_output
134
+ attr_accessor :generate_output_flag
135
+ attr_accessor :output_dir
136
+ attr_accessor :fail_on_warning
137
+ attr_accessor :fail_on_undocumented_objects
138
+ attr_accessor :show_public
139
+ attr_accessor :show_protected
140
+ attr_accessor :show_private
141
+ attr_accessor :hide_private_tag
142
+ attr_accessor :readme
143
+ attr_accessor :markup
144
+ attr_accessor :template
145
+ attr_accessor :template_path
146
+ attr_accessor :format
67
147
  attr_accessor :options
68
148
  attr_accessor :stats_options
69
149
 
@@ -71,10 +151,21 @@ module Toys
71
151
  tool(template.name) do
72
152
  desc "Run yardoc on the current project."
73
153
 
154
+ if template.generate_output_flag
155
+ flag :generate_output, "--[no-]output",
156
+ default: template.generate_output,
157
+ desc: "Whether to generate output"
158
+ else
159
+ set :generate_output, template.generate_output
160
+ end
161
+
74
162
  include :exec
163
+ include :terminal
75
164
 
76
165
  run do
166
+ gem("yard", *Array(template.gem_version))
77
167
  require "yard"
168
+
78
169
  files = []
79
170
  patterns = Array(template.files)
80
171
  patterns = ["lib/**/*.rb"] if patterns.empty?
@@ -83,15 +174,46 @@ module Toys
83
174
  end
84
175
  files.uniq!
85
176
 
86
- unless template.stats_options.empty?
87
- template.options << "--no-stats"
88
- template.stats_options << "--use-cache"
177
+ run_options = template.options.dup
178
+ stats_options = template.stats_options.dup
179
+ stats_options << "--list-undoc" if template.fail_on_undocumented_objects
180
+ run_options << "--fail-on-warning" if template.fail_on_warning
181
+ run_options << "--no-output" unless option(:generate_output)
182
+ run_options << "--output-dir" << template.output_dir if template.output_dir
183
+ run_options << "--no-public" unless template.show_public
184
+ run_options << "--protected" if template.show_protected
185
+ run_options << "--private" if template.show_private
186
+ run_options << "--no-private" if template.hide_private_tag
187
+ run_options << "-r" << template.readme if template.readme
188
+ run_options << "-m" << template.markup if template.markup
189
+ run_options << "-t" << template.template if template.template
190
+ run_options << "-p" << template.template_path if template.template_path
191
+ run_options << "-f" << template.format if template.format
192
+ unless stats_options.empty?
193
+ run_options << "--no-stats"
194
+ stats_options << "--use-cache"
89
195
  end
196
+ run_options.concat(files)
90
197
 
91
- yardoc = ::YARD::CLI::Yardoc.new
92
- yardoc.run(*(template.options + files))
93
- unless template.stats_options.empty?
94
- ::YARD::CLI::Stats.run(*template.stats_options)
198
+ result = exec_proc(proc { ::YARD::CLI::Yardoc.run(*run_options) })
199
+ if result.error?
200
+ puts("Yardoc encountered errors", :red, :bold) unless verbosity < 0
201
+ exit(1)
202
+ end
203
+ unless stats_options.empty?
204
+ result = exec_proc(proc { ::YARD::CLI::Stats.run(*stats_options) }, out: :capture)
205
+ puts result.captured_out
206
+ if result.error?
207
+ puts("Yardoc encountered errors", :red, :bold) unless verbosity < 0
208
+ exit(1)
209
+ end
210
+ exit_on_nonzero_status(result)
211
+ if template.fail_on_undocumented_objects
212
+ if result.captured_out =~ /Undocumented\sObjects:/
213
+ puts("Yardoc encountered undocumented objects", :red, :bold) unless verbosity < 0
214
+ exit(1)
215
+ end
216
+ end
95
217
  end
96
218
  end
97
219
  end