intent 0.5.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +10 -28
- data/bin/{review → intent} +1 -2
- data/bin/inventory +12 -0
- data/bin/project_doc +30 -0
- data/bin/projects +1 -1
- data/bin/projects_active +123 -0
- data/bin/todo +1 -1
- data/bin/todo_review +123 -0
- data/intent.gemspec +15 -7
- data/lib/gem_ext/todo-txt.rb +26 -2
- data/lib/intent/commands/base.rb +40 -0
- data/lib/intent/commands/errors.rb +7 -0
- data/lib/intent/commands/intent.rb +9 -0
- data/lib/intent/commands/inventory.rb +174 -0
- data/lib/intent/commands/projects.rb +34 -0
- data/lib/intent/commands/todo.rb +51 -0
- data/lib/intent/commands.rb +9 -0
- data/lib/intent/core.rb +184 -0
- data/lib/intent/desktop.rb +3 -0
- data/lib/intent/projects.rb +1 -1
- data/lib/intent/review.rb +10 -1
- data/lib/intent/text/inventory.help.txt +6 -0
- data/lib/intent/text/project.help.txt +7 -0
- data/lib/intent/text/projects.help.txt +9 -0
- data/lib/intent/text/todo.help.txt +15 -0
- data/lib/intent/todo.rb +3 -1
- data/lib/intent/ui/ttyui.rb +90 -0
- data/lib/intent/verbs/add.rb +21 -0
- data/lib/intent/verbs/cite.rb +14 -0
- data/lib/intent/verbs/install.rb +20 -0
- data/lib/intent/verbs/review.rb +131 -0
- data/lib/intent/{todo/manager.rb → verbs/todo.rb} +3 -16
- data/lib/intent/version.rb +1 -1
- data/lib/intent.rb +20 -3
- metadata +179 -32
- data/.travis.yml +0 -4
- data/CODE_OF_CONDUCT.md +0 -13
- data/lib/intent/projects/manager.rb +0 -20
- data/lib/intent/review/manager.rb +0 -17
- /data/lib/intent/{projects → verbs}/status.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a80e9d9082642b1f2325b40629ff95ffb096cdba644d0f2d5aa2af25541c2d2b
|
4
|
+
data.tar.gz: 90ed06f5afbf84636fbeb70e6fab66a4868dc0d485b751178b2ff31568315237
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4a23b8d4882af953e2d330c26388c91bb86513c1881192952998f6f74b5f49b682f4b609566ea18b0b6f0ad7517020ac15ccc22ce8756edc001ac5fc25c455b
|
7
|
+
data.tar.gz: cfc14324613fc505a6ec0a591e73f667dd3360b4ec1d8ee7f05d86813fcbaf5e645f12b917579adc6b046223dbc251f665f65b0cd70087dac39d59cc7adfdccf
|
data/.gitignore
CHANGED
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2016 Mark Rickerby
|
3
|
+
Copyright (c) 2016-2024 Mark Rickerby <https://maetl.net>
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,41 +1,23 @@
|
|
1
1
|
# Intent
|
2
2
|
|
3
|
-
|
3
|
+
Automation engine with todo.txt
|
4
4
|
|
5
|
-
|
5
|
+
This tool is mired deep in the obscurity and pedantry of the text-based computing culture that originated in the 1970s and still continues today. You probably don’t want to use this.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
Add this line to your application's Gemfile:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
gem 'intent'
|
13
9
|
```
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
$ bundle
|
18
|
-
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install intent
|
10
|
+
gem install intent
|
11
|
+
```
|
22
12
|
|
23
13
|
## Usage
|
24
14
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
-
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
-
|
33
|
-
## Contributing
|
34
|
-
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/intent. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
36
|
-
|
15
|
+
```
|
16
|
+
intent help
|
17
|
+
```
|
37
18
|
|
38
|
-
## License
|
19
|
+
## Copyright & License
|
39
20
|
|
40
|
-
|
21
|
+
Copyright 2024 Mark Rickerby <https://maetl.net>.
|
41
22
|
|
23
|
+
All documentation and modelling concepts are **CC BY-NC**. Source code and command line tools are MIT.
|
data/bin/{review → intent}
RENAMED
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
path = __FILE__
|
4
3
|
while File.symlink?(path)
|
5
4
|
path = File.expand_path(File.readlink(path), File.dirname(path))
|
@@ -8,4 +7,4 @@ $:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib'))
|
|
8
7
|
|
9
8
|
require 'intent'
|
10
9
|
|
11
|
-
Intent::
|
10
|
+
Intent::Dispatcher.exec_command(:intent, ARGV.dup)
|
data/bin/inventory
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
path = __FILE__
|
3
|
+
|
4
|
+
while File.symlink?(path)
|
5
|
+
path = File.expand_path(File.readlink(path), File.dirname(path))
|
6
|
+
end
|
7
|
+
|
8
|
+
$:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib'))
|
9
|
+
|
10
|
+
require 'intent'
|
11
|
+
|
12
|
+
Intent::Dispatcher.exec_command(:inventory, ARGV.dup)
|
data/bin/project_doc
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "tty-markdown"
|
3
|
+
require "tty-pager"
|
4
|
+
|
5
|
+
PROJECTS_PATH = File.dirname(ENV['TODO_TXT'])
|
6
|
+
|
7
|
+
class ProjectDocCommand
|
8
|
+
def self.print_help(output)
|
9
|
+
output.puts "Pass in a project name to read its main document."
|
10
|
+
output.puts "Future iterations could display a list of available documents."
|
11
|
+
# Command idea: Add milestone to document
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.run(args, output=STDOUT)
|
15
|
+
if args.empty?
|
16
|
+
print_help(output)
|
17
|
+
else
|
18
|
+
project_name = args.first.delete("^0–9a-z\-")
|
19
|
+
project_path = "#{PROJECTS_PATH}/#{project_name}"
|
20
|
+
|
21
|
+
if Dir.exists?(project_path)
|
22
|
+
pager = TTY::Pager.new
|
23
|
+
intent = File.read("#{project_path}/#{project_name}.md")
|
24
|
+
pager.page(TTY::Markdown.parse(intent))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ProjectDocCommand.run(ARGV.dup)
|
data/bin/projects
CHANGED
data/bin/projects_active
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "tty-box"
|
3
|
+
require "tty-screen"
|
4
|
+
require "tty-reader"
|
5
|
+
require "tty-cursor"
|
6
|
+
require "tty-pager"
|
7
|
+
require "pastel"
|
8
|
+
require "todo-txt"
|
9
|
+
|
10
|
+
list = Todo::List.new(ENV['TODO_TXT'])
|
11
|
+
|
12
|
+
box = TTY::Box.frame(
|
13
|
+
width: TTY::Screen.width,
|
14
|
+
height: TTY::Screen.height-1,
|
15
|
+
align: :center,
|
16
|
+
border: :thick,
|
17
|
+
style: {
|
18
|
+
fg: :bright_yellow,
|
19
|
+
border: {
|
20
|
+
fg: :white,
|
21
|
+
}
|
22
|
+
}
|
23
|
+
)
|
24
|
+
|
25
|
+
focus_index = 0
|
26
|
+
|
27
|
+
def truncate(str, width)
|
28
|
+
return str unless str.length >= width
|
29
|
+
|
30
|
+
"#{str.slice(0, width-3)}..."
|
31
|
+
end
|
32
|
+
|
33
|
+
def draw_card(top, item, focus)
|
34
|
+
|
35
|
+
style = unless top == focus
|
36
|
+
{ fg: :white, border: { fg: :white } }
|
37
|
+
else
|
38
|
+
{ fg: :bright_white, border: { fg: :bright_magenta, bg: :black } }
|
39
|
+
end
|
40
|
+
|
41
|
+
title = if top == focus
|
42
|
+
{bottom_right: "[x: close][enter: launch]"}
|
43
|
+
else
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
|
47
|
+
#pastel = Pastel.new
|
48
|
+
width = 90
|
49
|
+
|
50
|
+
TTY::Box.frame(width: width, height: 4, left: 4, title: title, border: :thick, style: style) do
|
51
|
+
"\s#{truncate(item[:title], 88)}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
projects = [
|
56
|
+
{ title: "maetl", index: File.read(File.expand_path("~/Documents/Projects/maetl/maetl.md")) },
|
57
|
+
{ title: "calyx", index: File.read(File.expand_path("~/Documents/Projects/calyx/calyx.md")) },
|
58
|
+
{ title: "yarrow", index: File.read(File.expand_path("~/Documents/Projects/yarrow/yarrow.md")) }
|
59
|
+
]
|
60
|
+
|
61
|
+
items_per_page = (TTY::Screen.height-1) / 4
|
62
|
+
|
63
|
+
# items = list.by_not_done.by_context("@reading").slice(0, items_per_page).map do |item|
|
64
|
+
# { title: item.text, href: item.text }
|
65
|
+
# end
|
66
|
+
|
67
|
+
$cursor = TTY::Cursor
|
68
|
+
#print $cursor.hide
|
69
|
+
|
70
|
+
def draw_list(items, focus)
|
71
|
+
buffer = []
|
72
|
+
items.each_with_index do |item, i|
|
73
|
+
buffer << draw_card(i, item, focus)
|
74
|
+
end
|
75
|
+
result = buffer.join("")
|
76
|
+
|
77
|
+
print $cursor.clear_screen + $cursor.move_to(0,0)
|
78
|
+
print result
|
79
|
+
end
|
80
|
+
|
81
|
+
draw_list(projects, focus_index)
|
82
|
+
|
83
|
+
reader = TTY::Reader.new(interrupt: :exit)
|
84
|
+
|
85
|
+
reader.on(:keyctrl_x, :keyescape) do
|
86
|
+
print $cursor.clear_screen + $cursor.move_to(0,0)
|
87
|
+
print $cursor.show
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
|
91
|
+
reader.on(:keytab, :keydown) do
|
92
|
+
if focus_index == projects.count - 1
|
93
|
+
focus_index = 0
|
94
|
+
else
|
95
|
+
focus_index += 1
|
96
|
+
end
|
97
|
+
draw_list(projects, focus_index)
|
98
|
+
end
|
99
|
+
|
100
|
+
reader.on(:keyup) do
|
101
|
+
if focus_index == 0
|
102
|
+
focus_index = projects.count - 1
|
103
|
+
else
|
104
|
+
focus_index -= 1
|
105
|
+
end
|
106
|
+
draw_list(projects, focus_index)
|
107
|
+
end
|
108
|
+
|
109
|
+
reader.on(:keypress) do |key|
|
110
|
+
# if key.value == "x"
|
111
|
+
# items.delete_at(focus_index)
|
112
|
+
# focus_index -= 1 if focus_index >= items.count
|
113
|
+
# draw_list(items, focus_index)
|
114
|
+
# end
|
115
|
+
end
|
116
|
+
|
117
|
+
reader.on(:keyenter) do
|
118
|
+
`chrome-cli open #{items[focus_index][:href]}`
|
119
|
+
end
|
120
|
+
|
121
|
+
loop do
|
122
|
+
reader.read_line(echo: false)
|
123
|
+
end
|
data/bin/todo
CHANGED
data/bin/todo_review
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "tty-box"
|
3
|
+
require "tty-screen"
|
4
|
+
require "tty-reader"
|
5
|
+
require "tty-cursor"
|
6
|
+
require "tty-pager"
|
7
|
+
require "pastel"
|
8
|
+
require "todo-txt"
|
9
|
+
|
10
|
+
list = Todo::List.new(ENV['TODO_TXT'])
|
11
|
+
|
12
|
+
box = TTY::Box.frame(
|
13
|
+
width: TTY::Screen.width,
|
14
|
+
height: TTY::Screen.height-1,
|
15
|
+
align: :center,
|
16
|
+
border: :thick,
|
17
|
+
style: {
|
18
|
+
fg: :bright_yellow,
|
19
|
+
border: {
|
20
|
+
fg: :white,
|
21
|
+
}
|
22
|
+
}
|
23
|
+
)
|
24
|
+
|
25
|
+
focus_index = 0
|
26
|
+
|
27
|
+
def truncate(str, width)
|
28
|
+
return str unless str.length >= width
|
29
|
+
|
30
|
+
"#{str.slice(0, width-3)}..."
|
31
|
+
end
|
32
|
+
|
33
|
+
def draw_card(top, item, focus)
|
34
|
+
|
35
|
+
style = unless top == focus
|
36
|
+
{ fg: :white, border: { fg: :white } }
|
37
|
+
else
|
38
|
+
{ fg: :bright_white, border: { fg: :bright_magenta, bg: :black } }
|
39
|
+
end
|
40
|
+
|
41
|
+
title = if top == focus
|
42
|
+
{bottom_right: "[x: close][enter: launch]"}
|
43
|
+
else
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
|
47
|
+
#pastel = Pastel.new
|
48
|
+
width = 90
|
49
|
+
|
50
|
+
TTY::Box.frame(width: width, height: 4, left: 4, title: title, border: :thick, style: style) do
|
51
|
+
"\s#{truncate(item[:title], 88)}\n\s#{truncate(item[:href], 88)}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
items = [
|
56
|
+
{ title: "maetl website", href: "https://maetl.net/" },
|
57
|
+
{ title: "tty-cursor on Github", href: "https://github.com/piotrmurach/tty-cursor" },
|
58
|
+
{ title: "Tangram Design", href: "https://tangram.co.nz" },
|
59
|
+
]
|
60
|
+
|
61
|
+
items_per_page = (TTY::Screen.height-1) / 4
|
62
|
+
|
63
|
+
items = list.by_not_done.by_context("@reading").slice(0, items_per_page).map do |item|
|
64
|
+
{ title: item.text, href: item.text }
|
65
|
+
end
|
66
|
+
|
67
|
+
$cursor = TTY::Cursor
|
68
|
+
print $cursor.hide
|
69
|
+
|
70
|
+
def draw_list(items, focus)
|
71
|
+
buffer = []
|
72
|
+
items.each_with_index do |item, i|
|
73
|
+
buffer << draw_card(i, item, focus)
|
74
|
+
end
|
75
|
+
result = buffer.join("")
|
76
|
+
|
77
|
+
print $cursor.clear_screen + $cursor.move_to(0,0)
|
78
|
+
print result
|
79
|
+
end
|
80
|
+
|
81
|
+
draw_list(items, focus_index)
|
82
|
+
|
83
|
+
reader = TTY::Reader.new(interrupt: :exit)
|
84
|
+
|
85
|
+
reader.on(:keyctrl_x, :keyescape) do
|
86
|
+
print $cursor.clear_screen + $cursor.move_to(0,0)
|
87
|
+
print $cursor.show
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
|
91
|
+
reader.on(:keytab, :keydown) do
|
92
|
+
if focus_index == items.count - 1
|
93
|
+
focus_index = 0
|
94
|
+
else
|
95
|
+
focus_index += 1
|
96
|
+
end
|
97
|
+
draw_list(items, focus_index)
|
98
|
+
end
|
99
|
+
|
100
|
+
reader.on(:keyup) do
|
101
|
+
if focus_index == 0
|
102
|
+
focus_index = items.count - 1
|
103
|
+
else
|
104
|
+
focus_index -= 1
|
105
|
+
end
|
106
|
+
draw_list(items, focus_index)
|
107
|
+
end
|
108
|
+
|
109
|
+
reader.on(:keypress) do |key|
|
110
|
+
if key.value == "x"
|
111
|
+
items.delete_at(focus_index)
|
112
|
+
focus_index -= 1 if focus_index >= items.count
|
113
|
+
draw_list(items, focus_index)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
reader.on(:keyenter) do
|
118
|
+
`chrome-cli open #{items[focus_index][:href]}`
|
119
|
+
end
|
120
|
+
|
121
|
+
loop do
|
122
|
+
reader.read_line(echo: false)
|
123
|
+
end
|
data/intent.gemspec
CHANGED
@@ -18,14 +18,22 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_runtime_dependency "todo-txt", "~> 0.
|
22
|
-
spec.add_runtime_dependency "pastel", "~> 0.
|
23
|
-
spec.add_runtime_dependency "git", "~> 1.
|
24
|
-
spec.add_runtime_dependency "terminal-notifier", "~>
|
21
|
+
spec.add_runtime_dependency "todo-txt", "~> 0.12"
|
22
|
+
spec.add_runtime_dependency "pastel", "~> 0.8"
|
23
|
+
spec.add_runtime_dependency "git", "~> 1.19.1"
|
24
|
+
spec.add_runtime_dependency "terminal-notifier", "~> 2.0"
|
25
25
|
spec.add_runtime_dependency "ghost", "~> 1.0.0"
|
26
|
+
spec.add_runtime_dependency "unicode_plot", "0.0.5"
|
27
|
+
spec.add_runtime_dependency "kdl", "1.0.3"
|
28
|
+
spec.add_runtime_dependency "sorted_set", "1.0.3"
|
29
|
+
spec.add_runtime_dependency "strings-ansi", "0.2.0"
|
30
|
+
spec.add_runtime_dependency "bibtex-ruby", "6.1.0"
|
31
|
+
spec.add_runtime_dependency "tty-prompt", "~> 0.23.1"
|
32
|
+
spec.add_runtime_dependency "tty-table", "~> 0.12.0"
|
33
|
+
spec.add_runtime_dependency "tty-tree", "~> 0.4.0"
|
34
|
+
spec.add_runtime_dependency "nanoid", "~> 2.0.0"
|
26
35
|
|
27
|
-
|
28
|
-
spec.add_development_dependency "
|
29
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
36
|
+
spec.add_development_dependency "bundler"
|
37
|
+
spec.add_development_dependency "rake"
|
30
38
|
spec.add_development_dependency "rspec"
|
31
39
|
end
|
data/lib/gem_ext/todo-txt.rb
CHANGED
@@ -10,13 +10,37 @@ class Todo::Task
|
|
10
10
|
# Completed tasks are rendered with a strikethrough
|
11
11
|
pastel.strikethrough(to_s)
|
12
12
|
else
|
13
|
-
|
14
|
-
|
13
|
+
[
|
14
|
+
pastel.red(print_priority),
|
15
|
+
pastel.yellow(created_on.to_s),
|
16
|
+
text,
|
17
|
+
pastel.bold.magenta(print_contexts),
|
18
|
+
pastel.bold.blue(print_projects),
|
19
|
+
pastel.bold.cyan(print_tags)
|
20
|
+
].reject { |item| !item || item.nil? || item.empty? }.join(' ')
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
24
|
+
def highlight_as_project
|
25
|
+
return to_s unless STDOUT.tty?
|
26
|
+
|
27
|
+
pastel = Pastel.new
|
28
|
+
[
|
29
|
+
pastel.bold.cyan(print_projects),
|
30
|
+
pastel.red(print_project_context)
|
31
|
+
].reject { |item| !item || item.nil? || item.empty? }.join(' ')
|
32
|
+
end
|
33
|
+
|
34
|
+
def text=(label)
|
35
|
+
@text = label
|
36
|
+
end
|
37
|
+
|
18
38
|
private
|
19
39
|
|
40
|
+
def print_project_context
|
41
|
+
'active' if contexts.include?('@active')
|
42
|
+
end
|
43
|
+
|
20
44
|
def print_open_task(pastel)
|
21
45
|
[
|
22
46
|
pastel.red(print_priority),
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Intent
|
2
|
+
module Commands
|
3
|
+
class Base
|
4
|
+
attr_reader :identity
|
5
|
+
attr_reader :documents
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@identity = strip_classname
|
9
|
+
@documents = ::Intent::Core::Documents.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def print_help(output)
|
13
|
+
output.puts(File.read(help_txt_path))
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_id
|
17
|
+
Nanoid.generate(size: 8, alphabet: ID_ALPHABET)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
T_CLASS_PREFIX = 'Intent::Commands::'
|
23
|
+
|
24
|
+
ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
25
|
+
|
26
|
+
def strip_classname
|
27
|
+
self.class.to_s.sub(T_CLASS_PREFIX, '').downcase
|
28
|
+
end
|
29
|
+
|
30
|
+
def help_txt_path
|
31
|
+
# TODO: does this work on Windows?
|
32
|
+
"#{__dir__}/../text/#{identity}.help.txt"
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_noun(type, label, tags)
|
36
|
+
Intent::Core::Noun.new(type, label, tags)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|