space 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,10 +6,6 @@ module Space
6
6
  autoload :App, 'space/app'
7
7
  autoload :Config, 'space/config'
8
8
  autoload :Events, 'space/events'
9
- autoload :Helpers, 'space/helpers'
10
- autoload :Logger, 'space/logger'
11
9
  autoload :Model, 'space/model'
12
- autoload :Screen, 'space/screen'
13
10
  autoload :Source, 'space/source'
14
- autoload :Tmux, 'space/tmux'
15
11
  end
@@ -30,8 +30,13 @@ module Space
30
30
  scope.each { |repo| yield repo }
31
31
  end
32
32
 
33
+ def in_repo(repo, &block)
34
+ puts "in #{repo.path}".ansi(:bold, :green)
35
+ Dir.chdir(repo.path, &block)
36
+ end
37
+
33
38
  def system(cmd)
34
- puts cmd
39
+ puts "#{cmd.ansi(:bold, :black)}\n"
35
40
  super
36
41
  end
37
42
 
@@ -4,16 +4,13 @@ module Space
4
4
  class Action
5
5
  class Execute < Action
6
6
  def run
7
- Events.sources.registered do
8
- in_scope do |repo|
9
- Dir.chdir(repo.path) do
10
- puts "in #{repo.path}\n".ansi(:bold, :green)
11
- system(*args)
12
- puts
13
- end
7
+ in_scope do |repo|
8
+ in_repo(repo) do
9
+ system(*args)
10
+ puts
14
11
  end
15
- confirm
16
12
  end
13
+ confirm
17
14
  end
18
15
  end
19
16
 
@@ -2,23 +2,19 @@ module Space
2
2
  class Action
3
3
  class Local < Action
4
4
  def run
5
- Events.sources.registered do
6
- scope.each do |repo|
7
- system "bundle config --global local.#{repo.name} #{repo.path}"
8
- end
9
- sleep 0.2 # not perfect, but fsevent is too slow to trigger
5
+ scope.each do |repo|
6
+ system "bundle config --global local.#{repo.name} #{repo.path}"
10
7
  end
8
+ confirm
11
9
  end
12
10
  end
13
11
 
14
12
  class Remote < Action
15
13
  def run
16
- Events.sources.registered do
17
- scope.each do |repo|
18
- system "bundle config --delete local.#{repo.name}"
19
- end
20
- sleep 0.2
14
+ scope.each do |repo|
15
+ system "bundle config --delete local.#{repo.name}"
21
16
  end
17
+ confirm
22
18
  end
23
19
  end
24
20
 
@@ -17,8 +17,9 @@ module Space
17
17
  def run(line)
18
18
  scope, type = parse(line)
19
19
  action = action_for(scope, type)
20
- action.run
21
- Events.flush
20
+ Events.sources.registered do
21
+ action.run
22
+ end
22
23
  end
23
24
 
24
25
  private
@@ -4,20 +4,17 @@ require 'thread'
4
4
 
5
5
  module Space
6
6
  class App
7
- attr_reader :name, :project, :screen
7
+ attr_reader :name, :project, :views
8
8
 
9
9
  def initialize(name)
10
10
  @name = name
11
11
  @project = Model::Project.new(name)
12
- @screen = Screen.new(project)
12
+ @views = [View::Progress.new(project), View::Dashboard.new(project)]
13
13
  end
14
14
 
15
15
  def run
16
- screen.display
17
16
  project.refresh
18
17
  cli_loop
19
- # Thread.new(&method(:cli_loop))
20
- # sleep
21
18
  puts
22
19
  end
23
20
 
@@ -26,7 +23,7 @@ module Space
26
23
  def cli_loop
27
24
  loop do
28
25
  print "\e[3;0H"
29
- line = Readline.readline(prompt, true) || break
26
+ line = Readline.readline(views.first.send(:prompt), true) || break
30
27
  handle(line)
31
28
  end
32
29
  rescue Exception => e
@@ -36,9 +33,5 @@ module Space
36
33
  def handle(line)
37
34
  Action::Handler.new(project).run(line) unless line.empty?
38
35
  end
39
-
40
- def prompt
41
- "#{project.repos.scoped? ? project.repos.scope.map { |r| r.name }.join(', ') : project.name} > "
42
- end
43
36
  end
44
37
  end
@@ -17,7 +17,7 @@ module Space
17
17
  end
18
18
  end
19
19
 
20
- define :template_dir => File.expand_path('../templates', __FILE__)
20
+ define :template_dir => File.expand_path('../view/templates', __FILE__)
21
21
 
22
22
  def paths
23
23
  @paths ||= repositories.map { |path| base_dir ? "#{base_dir}/#{path}" : path }
@@ -20,12 +20,6 @@ module Space
20
20
  subscriptions << Subscription.new(observer, types)
21
21
  end
22
22
 
23
- def flush
24
- event = events.first
25
- events.clear
26
- notify(event, false) if event
27
- end
28
-
29
23
  def notify(event)
30
24
  # log event
31
25
  subscriptions.each do |subscription|
@@ -15,19 +15,21 @@ module Space
15
15
  end
16
16
  end
17
17
 
18
- def register(source)
19
- Thread.exclusive do
20
- events.notify(:start) if sources.empty?
21
- sources << source
18
+ private
19
+
20
+ def register(source)
21
+ Thread.exclusive do
22
+ events.notify(:start) if sources.empty?
23
+ sources << source
24
+ end
22
25
  end
23
- end
24
26
 
25
- def unregister(source)
26
- Thread.exclusive do
27
- sources.delete(source)
28
- events.notify(:finish) if sources.empty?
27
+ def unregister(source)
28
+ Thread.exclusive do
29
+ sources.delete(source)
30
+ events.notify(:finish) if sources.empty?
31
+ end
29
32
  end
30
- end
31
33
  end
32
34
  end
33
35
  end
@@ -2,6 +2,7 @@ module Space
2
2
  module Model
3
3
  class Project
4
4
  autoload :Bundler, 'space/model/project/bundler'
5
+ autoload :Tmux, 'space/model/project/tmux'
5
6
 
6
7
  include Events
7
8
 
@@ -0,0 +1,16 @@
1
+ # TODO make this a source?
2
+ #
3
+ module Space
4
+ module Model
5
+ class Project
6
+ module Tmux
7
+ class << self
8
+ def windows
9
+ windows = `tmux list-windows -F '#W'`.split("\n")
10
+ windows unless windows.empty?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,7 +2,6 @@ module Space
2
2
  module Source
3
3
  autoload :Command, 'space/source/command'
4
4
  autoload :Watch, 'space/source/watch'
5
- autoload :Watcher, 'space/source/watcher'
6
5
 
7
6
  module ClassMethods
8
7
  def commands(commands = nil)
@@ -14,7 +13,7 @@ module Space
14
13
  end
15
14
  end
16
15
 
17
- include Events, Watcher
16
+ include Events
18
17
 
19
18
  class << self
20
19
  def included(base)
@@ -22,11 +21,12 @@ module Space
22
21
  end
23
22
  end
24
23
 
25
- attr_reader :results
24
+ attr_reader :path, :results
26
25
 
27
26
  def initialize(path)
27
+ @path = path
28
28
  @results = {}
29
- super
29
+ watch
30
30
  end
31
31
 
32
32
  def commands
@@ -35,10 +35,6 @@ module Space
35
35
  end
36
36
  end
37
37
 
38
- def result(key)
39
- results[key] || ''
40
- end
41
-
42
38
  def refresh
43
39
  commands.each { |key, command| command.refresh }
44
40
  end
@@ -47,5 +43,27 @@ module Space
47
43
  results[key] = result
48
44
  notify(:update)
49
45
  end
46
+
47
+ private
48
+
49
+ def result(key)
50
+ results[key] || ''
51
+ end
52
+
53
+ def watch
54
+ watchers.map(&:run)
55
+ end
56
+
57
+ def watchers
58
+ @watchers ||= watched_paths.map do |path|
59
+ Watch.new(path) { |paths| refresh }
60
+ end
61
+ end
62
+
63
+ def watched_paths
64
+ @watched_paths ||= self.class.watch.map do |path|
65
+ path[0, 1] == '~' ? path : "#{self.path}/#{path}"
66
+ end
67
+ end
50
68
  end
51
69
  end
@@ -6,12 +6,11 @@ module Space
6
6
  LATENCY = 0.1
7
7
  NO_DEFER = FALSE
8
8
 
9
- attr_reader :path, :callback, :suspended, :fsevent
9
+ attr_reader :path, :callback, :fsevent
10
10
 
11
11
  def initialize(path, &block)
12
12
  @path = File.expand_path(path)
13
13
  @callback = block
14
- # @suspended = []
15
14
  @fsevent = FSEvent.new
16
15
  end
17
16
 
@@ -23,23 +22,16 @@ module Space
23
22
  self
24
23
  end
25
24
 
26
- # def suspended?
27
- # !suspended.empty?
28
- # end
29
-
30
- # def suspend
31
- # suspended << true
32
- # end
33
-
34
- # def unsuspend
35
- # suspended.pop
36
- # end
37
-
38
25
  private
39
26
 
40
27
  def watch
41
28
  fsevent.watch(path, file: file?, latency: LATENCY, no_defer: NO_DEFER) do |paths|
42
- unless git_dir?(paths)
29
+ # git touches the .git dir on `git status` as we use this command
30
+ # internally we need to ignore this. as no other relevant action
31
+ # only touches the .git dir, we can just skip it.
32
+ paths.reject!(&method(:git_dir?))
33
+
34
+ unless paths.empty?
43
35
  log "=> WATCH triggered: #{paths.inspect}"
44
36
  fsevent.stop
45
37
  callback.call(paths)
@@ -55,8 +47,8 @@ module Space
55
47
  File.file?(path)
56
48
  end
57
49
 
58
- def git_dir?(paths)
59
- paths.size == 1 && File.basename(paths.first) == '.git'
50
+ def git_dir?(path)
51
+ File.basename(path) == '.git'
60
52
  end
61
53
  end
62
54
  end
@@ -1,3 +1,3 @@
1
1
  module Space
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -0,0 +1,57 @@
1
+ require 'erb'
2
+
3
+ module Space
4
+ class View
5
+ autoload :Helpers, 'space/view/helpers'
6
+ autoload :Progress, 'space/view/progress'
7
+ autoload :Dashboard, 'space/view/dashboard'
8
+
9
+ include Helpers
10
+
11
+ attr_reader :project
12
+
13
+ def initialize(project)
14
+ @project = project
15
+ end
16
+
17
+ def notify(event)
18
+ send(:"on_#{event}")
19
+ end
20
+
21
+ private
22
+
23
+ def render_header
24
+ print "Project #{project.name}\n\n", :at => [0, 0]
25
+ render_prompt
26
+ move 0, 5
27
+ end
28
+
29
+ def render_prompt
30
+ print prompt, :at => [0, 3]
31
+ print "\e[0K", :at => [prompt.size + 1, 3]
32
+ end
33
+
34
+ def render_template(name, assigns)
35
+ path = "#{project.config.template_dir}/#{name}.erb"
36
+ print Template.new(path).render(assigns)
37
+ end
38
+
39
+ def clear
40
+ print "\e[2J" # clear entire screen
41
+ end
42
+
43
+ def print(string, options = {})
44
+ move(*options[:at]) if options.key?(:at)
45
+ super(string)
46
+ end
47
+
48
+ def move(x, y)
49
+ print "\e[#{y};#{x}H"
50
+ end
51
+
52
+ def prompt
53
+ "#{project.repos.scoped? ? project.repos.scope.map(&:name).join(', ') : project.name} > "
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,31 @@
1
+ module Space
2
+ class View
3
+ class Dashboard < View
4
+ def initialize(*)
5
+ Events.subscribe(self, :finish)
6
+ super
7
+ end
8
+
9
+ private
10
+
11
+ def on_finish
12
+ App.log 'RENDER dashboard'
13
+ clear
14
+ render_header
15
+ render_repos
16
+ render_prompt
17
+ end
18
+
19
+ def render_repos
20
+ project.repos.scope.self_and_deps.each do |repo|
21
+ render_repo(repo)
22
+ end
23
+ end
24
+
25
+ def render_repo(repo)
26
+ assigns = { project: project, repos: project.repos, repo: repo, git: repo.git, bundle: repo.bundle }
27
+ render_template(:repo, assigns)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ require 'ansi/core'
3
+ require 'core_ext/string/wrap'
4
+
5
+ module Space
6
+ class View
7
+ module Helpers
8
+ def project_title
9
+ "Project: #{name}".ansi(:bold)
10
+ end
11
+
12
+ def tableize(string)
13
+ string.split(' ')
14
+ project.local_repos.join(', ')
15
+ end
16
+
17
+ def repo_name
18
+ repo.name.ansi(:bold)
19
+ end
20
+
21
+ def repo_status
22
+ [git.branch, git.commit, repo_local].compact.join(', ')
23
+ end
24
+
25
+ def repo_local
26
+ 'L'.ansi(:bold, :red) if repo_local?
27
+ end
28
+
29
+ def repo_local?
30
+ project.local_repos.include?(repo.name)
31
+ end
32
+
33
+ def repo_selected?
34
+ repos.scoped? && repos.scope.include?(repo)
35
+ end
36
+
37
+ def git_status
38
+ "Git: #{format_boolean(git.clean?)}#{git_ahead if git.ahead?}"
39
+ end
40
+
41
+ def git_ahead
42
+ " #{git.ahead} commit#{'s' if git.ahead > 1} ahead".ansi(:yellow)
43
+ end
44
+
45
+ def bundle_status
46
+ "Bundle: #{format_boolean(bundle.clean?)}"
47
+ end
48
+
49
+ def bundle_info
50
+ bundle.info.ansi(:red) unless bundle.clean?
51
+ end
52
+
53
+ def bundle_deps
54
+ bundle.deps.map { |dep| "• #{dep.ref} #{format_boolean(dep.fresh?)} #{dep.name}" }.join("\n")
55
+ end
56
+
57
+ def format_boolean(value)
58
+ value ? '✔'.ansi(:green, :bold) : '⚡'.ansi(:red, :bold)
59
+ end
60
+
61
+ def i(string, width = 2)
62
+ lines = string.split("\n")
63
+ lines = lines.map { |line| line.wrap(80).split("\n") }.flatten
64
+ lines = lines.map { |line| [' ' * width, line].join }
65
+ lines.join("\n")
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,25 +1,25 @@
1
1
  module Space
2
- class Screen
2
+ class View
3
3
  class Progress < View
4
4
  def initialize(*)
5
- super
6
5
  Events.subscribe(self, :start, :update)
6
+ super
7
+ render
7
8
  end
8
9
 
9
- def notify(event)
10
- case event
11
- when :start
10
+ private
11
+
12
+ def render
12
13
  clear
13
- when :update
14
- print '.'
14
+ render_header
15
15
  end
16
- end
17
16
 
18
- private
17
+ def on_start
18
+ render
19
+ end
19
20
 
20
- def clear
21
- move 0, 5
22
- print "\e[0J" # clear from cursor down
21
+ def on_update
22
+ print '.'
23
23
  end
24
24
  end
25
25
  end
@@ -0,0 +1,33 @@
1
+ module Space
2
+ class View
3
+ class Template
4
+ class << self
5
+ def [](path)
6
+ templates[path] ||= ERB.new(File.read(path), nil, '%<>-')
7
+ end
8
+
9
+ def templates
10
+ @templates ||= {}
11
+ end
12
+ end
13
+
14
+ include Helpers
15
+
16
+ attr_reader :template
17
+
18
+ def initialize(path)
19
+ @template = Template[path]
20
+ end
21
+
22
+ def render(assigns)
23
+ assigns.each { |key, value| assign(key, value) }
24
+ template.result(binding)
25
+ end
26
+
27
+ def assign(key, value)
28
+ instance_variable_set(:"@#{key}", value)
29
+ (class << self; self; end).send(:attr_reader, key)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ y%= project_title %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: space
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -33,10 +33,10 @@ files:
33
33
  - lib/space/events/sources.rb
34
34
  - lib/space/events/subscription.rb
35
35
  - lib/space/events.rb
36
- - lib/space/helpers.rb
37
36
  - lib/space/logger.rb
38
37
  - lib/space/model/project/bundler/config.rb
39
38
  - lib/space/model/project/bundler.rb
39
+ - lib/space/model/project/tmux.rb
40
40
  - lib/space/model/project.rb
41
41
  - lib/space/model/repo/bundle.rb
42
42
  - lib/space/model/repo/dependency.rb
@@ -46,18 +46,17 @@ files:
46
46
  - lib/space/model/repos/scope.rb
47
47
  - lib/space/model/repos.rb
48
48
  - lib/space/model.rb
49
- - lib/space/screen/dashboard.rb
50
- - lib/space/screen/progress.rb
51
- - lib/space/screen/view.rb
52
- - lib/space/screen.rb
53
49
  - lib/space/source/command.rb
54
50
  - lib/space/source/watch.rb
55
- - lib/space/source/watcher.rb
56
51
  - lib/space/source.rb
57
- - lib/space/templates/header.erb
58
- - lib/space/templates/repo.erb
59
- - lib/space/tmux.rb
60
52
  - lib/space/version.rb
53
+ - lib/space/view/dashboard.rb
54
+ - lib/space/view/helpers.rb
55
+ - lib/space/view/progress.rb
56
+ - lib/space/view/template.rb
57
+ - lib/space/view/templates/header.erb
58
+ - lib/space/view/templates/repo.erb
59
+ - lib/space/view.rb
61
60
  - lib/space.rb
62
61
  - Gemfile
63
62
  - Gemfile.lock
@@ -1,68 +0,0 @@
1
- # encoding: UTF-8
2
- require 'ansi/core'
3
- require 'core_ext/string/wrap'
4
-
5
- module Space
6
- module Helpers
7
- def project_title
8
- "Project: #{name}".ansi(:bold)
9
- end
10
-
11
- def tableize(string)
12
- string.split(' ')
13
- project.local_repos.join(', ')
14
- end
15
-
16
- def repo_name
17
- repo.name.ansi(:bold)
18
- end
19
-
20
- def repo_status
21
- [git.branch, git.commit, repo_local].compact.join(', ')
22
- end
23
-
24
- def repo_local
25
- 'L'.ansi(:bold, :red) if repo_local?
26
- end
27
-
28
- def repo_local?
29
- project.local_repos.include?(repo.name)
30
- end
31
-
32
- def repo_selected?
33
- repos.scoped? && repos.scope.include?(repo)
34
- end
35
-
36
- def git_status
37
- "Git: #{format_boolean(git.clean?)}#{git_ahead if git.ahead?}"
38
- end
39
-
40
- def git_ahead
41
- " #{git.ahead} commit#{'s' if git.ahead > 1} ahead".ansi(:yellow)
42
- end
43
-
44
- def bundle_status
45
- "Bundle: #{format_boolean(bundle.clean?)}"
46
- end
47
-
48
- def bundle_info
49
- bundle.info.ansi(:red) unless bundle.clean?
50
- end
51
-
52
- def bundle_deps
53
- bundle.deps.map { |dep| "• #{dep.ref} #{format_boolean(dep.fresh?)} #{dep.name}" }.join("\n")
54
- end
55
-
56
- def format_boolean(value)
57
- value ? '✔'.ansi(:green, :bold) : '⚡'.ansi(:red, :bold)
58
- end
59
-
60
- def i(string, width = 2)
61
- lines = string.split("\n")
62
- lines = lines.map { |line| line.wrap(80).split("\n") }.flatten
63
- lines = lines.map { |line| [' ' * width, line].join }
64
- lines.join("\n")
65
- end
66
- end
67
- end
68
-
@@ -1,49 +0,0 @@
1
- module Space
2
- class Screen
3
- autoload :Progress, 'space/screen/progress'
4
- autoload :Dashboard, 'space/screen/dashboard'
5
- autoload :View, 'space/screen/view'
6
-
7
- attr_reader :project, :view
8
-
9
- def initialize(project)
10
- @project = project
11
- render_header
12
- end
13
-
14
- def display
15
- @views = [Progress.new(project), Dashboard.new(project)]
16
- end
17
-
18
- # def render
19
- # view.render
20
- # move prompt.size + 1, 3
21
- # end
22
-
23
- # def notify(event)
24
- # view.notify(event)
25
- # end
26
-
27
- private
28
-
29
- def render_header
30
- print "\e[2J" # clear entire screen
31
- move 0, 0
32
- puts "Project #{project.name}\n\n"
33
- puts prompt
34
- end
35
-
36
- def move(x, y)
37
- print "\e[#{y};#{x}H"
38
- end
39
-
40
- def prompt
41
- "#{project.repos.scoped? ? project.repos.scope.map { |r| r.name }.join(', ') : project.name} > "
42
- end
43
-
44
- # def create(screen)
45
- # self.class.const_get(screen.to_s.capitalize).new(project)
46
- # end
47
- end
48
- end
49
-
@@ -1,44 +0,0 @@
1
- module Space
2
- class Screen
3
- class Dashboard < View
4
- def initialize(*)
5
- Events.subscribe(self, :finish)
6
- super
7
- end
8
-
9
- def notify(event)
10
- render
11
- end
12
-
13
- private
14
-
15
- def render
16
- App.log 'RENDER dashboard'
17
- clear
18
- render_repos
19
- move prompt.size + 1, 3
20
- print "\e[0K"
21
- end
22
-
23
- def clear
24
- move 0, 4
25
- print "\e[J" # clear from cursor down
26
- move 0, 5
27
- end
28
-
29
- def prompt
30
- "#{project.repos.scoped? ? project.repos.scope.map { |r| r.name }.join(', ') : project.name} > "
31
- end
32
-
33
- def render_repos
34
- project.repos.scope.self_and_deps.each do |repo|
35
- render_template(:repo, assigns(repo))
36
- end
37
- end
38
-
39
- def assigns(repo)
40
- { repos: project.repos, repo: repo, git: repo.git, bundle: repo.bundle }
41
- end
42
- end
43
- end
44
- end
@@ -1,39 +0,0 @@
1
- require 'erb'
2
-
3
- module Space
4
- class Screen
5
- class View
6
- include Helpers
7
-
8
- attr_reader :project
9
-
10
- def initialize(project)
11
- @project = project
12
- end
13
-
14
- private
15
-
16
- def move(x, y)
17
- print "\e[#{y};#{x}H"
18
- end
19
-
20
- def render_template(name, assigns)
21
- assigns.each { |name, value| assign(name, value) }
22
- print template(name).result(binding)
23
- end
24
-
25
- def assign(key, value)
26
- instance_variable_set(:"@#{key}", value)
27
- (class << self; self; end).send(:attr_reader, key)
28
- end
29
-
30
- def templates
31
- @templates ||= {}
32
- end
33
-
34
- def template(name)
35
- templates[name] ||= ERB.new(File.read("#{project.config.template_dir}/#{name}.erb"), nil, '%<>-')
36
- end
37
- end
38
- end
39
- end
@@ -1,32 +0,0 @@
1
- module Space
2
- module Source
3
- module Watcher
4
- attr_reader :path
5
-
6
- def initialize(path)
7
- @path = path
8
- start
9
- end
10
-
11
- def watched_paths
12
- @watched_paths ||= self.class.watch.map do |path|
13
- path[0, 1] == '~' ? path : "#{self.path}/#{path}"
14
- end
15
- end
16
-
17
- private
18
-
19
- def start
20
- watchers.map(&:run)
21
- end
22
-
23
- def watchers
24
- @watchers ||= watched_paths.map do |path|
25
- Watch.new(path) do |paths|
26
- refresh
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1 +0,0 @@
1
- <%= project_title %>
@@ -1,11 +0,0 @@
1
- module Space
2
- module Tmux
3
- class << self
4
- def windows
5
- windows = `tmux list-windows -F '#W'`.split("\n")
6
- windows unless windows.empty?
7
- end
8
- end
9
- end
10
- end
11
-