a4tools 1.2.7
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 +7 -0
- data/.bundle/install.log +38 -0
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +38 -0
- data/a4tools.gemspec +38 -0
- data/bin/deploy_latest_clients +32 -0
- data/bin/devsite_config_server +48 -0
- data/bin/netshell +23 -0
- data/bin/update_server +101 -0
- data/bin/usher +54 -0
- data/lib/a4tools.rb +61 -0
- data/lib/a4tools/version.rb +3 -0
- data/lib/acres_client.rb +376 -0
- data/lib/clients/caching_client.rb +151 -0
- data/lib/clients/deployment_client.rb +53 -0
- data/lib/clients/kai_config_client.rb +39 -0
- data/lib/clients/usher_client.rb +72 -0
- data/lib/clients/usher_mgmt_client.rb +201 -0
- data/lib/event_manager.rb +24 -0
- data/lib/events.json +1 -0
- data/lib/net_shell/builtin_command.rb +312 -0
- data/lib/net_shell/builtin_commands/build.rb +251 -0
- data/lib/net_shell/builtin_commands/cd.rb +12 -0
- data/lib/net_shell/builtin_commands/connect.rb +122 -0
- data/lib/net_shell/builtin_commands/deploy.rb +280 -0
- data/lib/net_shell/builtin_commands/disconnect.rb +15 -0
- data/lib/net_shell/builtin_commands/excerpt.rb +97 -0
- data/lib/net_shell/builtin_commands/exit.rb +7 -0
- data/lib/net_shell/builtin_commands/get.rb +38 -0
- data/lib/net_shell/builtin_commands/help.rb +40 -0
- data/lib/net_shell/builtin_commands/host.rb +126 -0
- data/lib/net_shell/builtin_commands/inject.rb +42 -0
- data/lib/net_shell/builtin_commands/jsoncache.rb +80 -0
- data/lib/net_shell/builtin_commands/kai_event.rb +151 -0
- data/lib/net_shell/builtin_commands/persist.rb +24 -0
- data/lib/net_shell/builtin_commands/pwd.rb +6 -0
- data/lib/net_shell/builtin_commands/recap.rb +188 -0
- data/lib/net_shell/builtin_commands/references.rb +63 -0
- data/lib/net_shell/builtin_commands/select.rb +36 -0
- data/lib/net_shell/builtin_commands/send.rb +74 -0
- data/lib/net_shell/builtin_commands/set.rb +29 -0
- data/lib/net_shell/builtin_commands/show.rb +183 -0
- data/lib/net_shell/builtin_commands/site.rb +122 -0
- data/lib/net_shell/builtin_commands/ssh.rb +62 -0
- data/lib/net_shell/builtin_commands/talk.rb +90 -0
- data/lib/net_shell/builtin_commands/translate.rb +45 -0
- data/lib/net_shell/builtin_commands/unset.rb +14 -0
- data/lib/net_shell/builtin_commands/usher.rb +55 -0
- data/lib/net_shell/builtin_commands/usher_device.rb +39 -0
- data/lib/net_shell/builtin_commands/usher_site.rb +245 -0
- data/lib/net_shell/builtin_commands/usherm_connect.rb +21 -0
- data/lib/net_shell/colors.rb +149 -0
- data/lib/net_shell/command.rb +97 -0
- data/lib/net_shell/io.rb +132 -0
- data/lib/net_shell/net_shell.rb +396 -0
- data/lib/net_shell/prompt.rb +335 -0
- data/lib/object_builder/definitions/app_info_for_script.rb +83 -0
- data/lib/object_builder/definitions/connection_request.rb +28 -0
- data/lib/object_builder/definitions/device_info_for_system.rb +37 -0
- data/lib/object_builder/object_builder.rb +145 -0
- data/lib/talk.json +1 -0
- data/lib/talk_consumer.rb +235 -0
- metadata +279 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'talk'
|
2
|
+
|
3
|
+
category "Talk"
|
4
|
+
description "Select a given version of Talk"
|
5
|
+
usage "[branch_name]"
|
6
|
+
help <<-EOS
|
7
|
+
Selects a given version of Talk for use in netshell.
|
8
|
+
EOS
|
9
|
+
|
10
|
+
opt :repo, "Use the indicated local repository instead of default"
|
11
|
+
opt :commit, "Select a Talk version in terms of a git commit hash instead of a branch", :type => :string
|
12
|
+
opt :update, "Ensure that the acres4/talk repository is up-to-date"
|
13
|
+
opt :jeb, "Select a Talk version in terms of a jeb instead of a branch", :type => :string
|
14
|
+
opt :talkversion, "Use a specific version of maketalk", :type => :string
|
15
|
+
|
16
|
+
tab :commit do
|
17
|
+
return list_commits.map { |commit| commit[:hash] }
|
18
|
+
end
|
19
|
+
|
20
|
+
tab :jeb do
|
21
|
+
return list_commits.map { |commit| commit[:jeb] }
|
22
|
+
end
|
23
|
+
|
24
|
+
tab 0 do
|
25
|
+
return list_branches
|
26
|
+
end
|
27
|
+
|
28
|
+
validate do
|
29
|
+
return true if args.length == 2 and !params[:jeb] and !params[:commit]
|
30
|
+
return true if args.length == 1 and (params[:jeb] or params[:commit])
|
31
|
+
end
|
32
|
+
|
33
|
+
run do
|
34
|
+
clone_repo unless repo_exists?
|
35
|
+
fetch if params[:update]
|
36
|
+
target = params[:jeb] || params[:commit] || args[1]
|
37
|
+
checkout(target)
|
38
|
+
make_talk
|
39
|
+
""
|
40
|
+
end
|
41
|
+
|
42
|
+
###
|
43
|
+
|
44
|
+
def repo
|
45
|
+
params[:repo] || @shell.shelldir("talk")
|
46
|
+
end
|
47
|
+
|
48
|
+
def talk_json_path
|
49
|
+
$localtalk
|
50
|
+
end
|
51
|
+
|
52
|
+
def repo_exists?
|
53
|
+
File.exist?(File.join(repo, ".git"))
|
54
|
+
end
|
55
|
+
|
56
|
+
def fetch
|
57
|
+
`cd #{repo} && git fetch`
|
58
|
+
end
|
59
|
+
|
60
|
+
def checkout(id)
|
61
|
+
id = Jebediah.new.process(id)[:result] if params[:jeb]
|
62
|
+
`cd #{repo} && git checkout origin/#{id}`
|
63
|
+
end
|
64
|
+
|
65
|
+
def make_talk
|
66
|
+
version = params[:talkversion] ? " _#{params[:talkversion]}_" : ""
|
67
|
+
`cd #{repo} && maketalk#{version} --upgrade --json info > #{talk_json_path}`
|
68
|
+
refresh_talk
|
69
|
+
end
|
70
|
+
|
71
|
+
def clone_repo
|
72
|
+
puts "Cloning respository into #{repo}"
|
73
|
+
`cd #{File.join(repo, "..")} && git clone git@github.com:acres4/talk`
|
74
|
+
end
|
75
|
+
|
76
|
+
def list_commits
|
77
|
+
return [] unless repo_exists?
|
78
|
+
jeb = Jebediah.new
|
79
|
+
`cd #{repo} && git log --pretty=format:"%an:%h:%s"`.split("\n").map do |commit|
|
80
|
+
components = commit.split(":")
|
81
|
+
{ author:components[0], hash:components[1], jeb:jeb.process(components[1])[:result].join(" "), notes:components[2] }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def list_branches
|
86
|
+
return [] unless repo_exists?
|
87
|
+
branches = `cd #{repo} && git branch -a --no-color`.split("\n").map { |x| x.gsub(/^\*? */,"").gsub(/^.*-> /,"").gsub(/^(remotes\/)?origin\//,"") }
|
88
|
+
branches &= branches # remove dupes
|
89
|
+
branches.sort
|
90
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
category "Talk"
|
2
|
+
description "Find talk entities matching a constant value or string"
|
3
|
+
usage "value"
|
4
|
+
|
5
|
+
help <<-EOS
|
6
|
+
Attempts to find a string or number in a Talk glossary or enumeration. All matching constants are displayed. Constants are case-sensitive.
|
7
|
+
|
8
|
+
Example:
|
9
|
+
Show all constants equal to 10
|
10
|
+
#{command} 10
|
11
|
+
|
12
|
+
Show all terms equal to Mercury
|
13
|
+
#{command} Mercury
|
14
|
+
|
15
|
+
EOS
|
16
|
+
|
17
|
+
validate { args.length == 2 }
|
18
|
+
|
19
|
+
tab 0 do
|
20
|
+
(talk.definition[:glossary].inject([]) { |terms, glossary| terms + glossary[:term] }).map { |t| t[:value] }
|
21
|
+
end
|
22
|
+
|
23
|
+
run { translate(args[1]) }
|
24
|
+
|
25
|
+
###
|
26
|
+
|
27
|
+
def translate(value)
|
28
|
+
is_numeric = (not(value.is_a?(String)) or value.match(/^[-+]?[0-9]+(.[0-9]+)?$/) != nil)
|
29
|
+
|
30
|
+
candidates = case is_numeric
|
31
|
+
when true
|
32
|
+
talk.definition[:enumeration].inject([]) do |c, enum|
|
33
|
+
c + (enum[:constant].select { |constant| constant[:value] == value.to_f }).map { |x| { collection:enum, constant:x } }
|
34
|
+
end
|
35
|
+
when false
|
36
|
+
talk.definition[:glossary].inject([]) do |c, glossary|
|
37
|
+
c + (glossary[:term].select { |term| term[:value] == value }).map { |x| { collection:glossary, constant:x } }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return "No matches for #{value}" if candidates.empty?
|
42
|
+
|
43
|
+
(candidates.map { |item| "#{item[:constant][:name].style(:constant_name)} (#{talk.truncated_name item[:collection][:name].style(:collection_name)}): #{item[:constant][:description]}" }).join("\n")
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
category "Usher"
|
2
|
+
description "Determine usher information for current IP and serial number"
|
3
|
+
usage "[serial_number]"
|
4
|
+
|
5
|
+
help <<-EOS
|
6
|
+
Prints usher information for clients requesting from the specified IP address and serial number.
|
7
|
+
|
8
|
+
If no IP or serial number are supplied, #{command.style(:command)} uses the host's actual IP address and the "#{"serial".style(:environment)}" environment variable.
|
9
|
+
EOS
|
10
|
+
|
11
|
+
opt :full, "Instruct usher to give all possible hosts instead of trying to guess which host is appropriate. (e.g. use \"#{"usherAlt".style(:method_name)}\" method)"
|
12
|
+
opt :json, "Print result as JSON"
|
13
|
+
opt :url, "Use usher mirror at specified URL", :type => :string
|
14
|
+
opt :ip, "Use usher as if coming from IP address", :type => :string
|
15
|
+
|
16
|
+
tab 0 do
|
17
|
+
(usherm[:devSiteInfoSync][:devSiteInfoArray].map { |info| info[:serialNumber] }) rescue []
|
18
|
+
end
|
19
|
+
|
20
|
+
run do
|
21
|
+
params[:serial] = args[1] if args.length > 0
|
22
|
+
result = A4Tools::UsherClient.new(params[:url]).list_servers_raw(params)
|
23
|
+
return params[:json] ? result.body : render_result(result)
|
24
|
+
end
|
25
|
+
|
26
|
+
###
|
27
|
+
|
28
|
+
def render_result(response)
|
29
|
+
return ("Unable to contact usher") if response.nil?
|
30
|
+
return "Usher returned status #{response.code}" if response.code.to_i < 200 or response.code.to_i >= 300
|
31
|
+
begin
|
32
|
+
payload = JSON.parse(response.body)
|
33
|
+
return ("Usher returned non-JSON RPC response") unless payload["jsonrpc"] == "2.0"
|
34
|
+
return ("Usher returned error: \"#{payload["error"]}\"") unless payload["error"].nil?
|
35
|
+
return ("Usher did not include result") if payload["result"].nil?
|
36
|
+
return ("Usher server returned non-usher response") unless payload["result"]["className"] == "com.acres4.common.info.usher.UsherResponse"
|
37
|
+
return ("Usher response did not include body") if payload["result"]["body"].nil?
|
38
|
+
return render_success(payload["result"]["body"])
|
39
|
+
rescue JSON::ParserError
|
40
|
+
return ("Usher returned non-JSON response")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_success(result)
|
45
|
+
s = " Site ID: #{result["siteID"]}\n"
|
46
|
+
s += " Site name: #{result["siteName"]}\n"
|
47
|
+
s += "Remote address: #{result["remoteAddr"]}\n\n"
|
48
|
+
|
49
|
+
result["hosts"].each do |host|
|
50
|
+
s += "Product: #{host["product"]} (#{host["host"]}:#{host["port"]})\n\t#{host["url"]}, #{host["ctx"]}, System #{host["systemId"]}\n\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
s
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
category "Usher"
|
2
|
+
description "Manage development devices in Usher"
|
3
|
+
usage [
|
4
|
+
"[siteId] -- list development devices in usher",
|
5
|
+
"serial siteId [comment] -- update development device with specified serial number"
|
6
|
+
]
|
7
|
+
|
8
|
+
help <<-EOS
|
9
|
+
Updates the development device with the specified serial in UsherM to use the specified site ID. If a comment supplied, the device's comment field is updated to the supplied comment.
|
10
|
+
|
11
|
+
If no such serial is registered, a new registration is created.
|
12
|
+
|
13
|
+
Must have previously connected to UsherM using #{"usherm_connect".style(:environment)}.
|
14
|
+
EOS
|
15
|
+
|
16
|
+
validate do
|
17
|
+
return show_error("must connect usherm first") if usherm.nil?
|
18
|
+
args.length <= 4
|
19
|
+
end
|
20
|
+
|
21
|
+
tab 0 do
|
22
|
+
usherm[:devSiteInfoSync][:devSiteInfoArray].map { |info| info[:serialNumber] } rescue []
|
23
|
+
end
|
24
|
+
|
25
|
+
run do
|
26
|
+
if args.length == 1 or args.length == 2 then
|
27
|
+
usherm.ensure_fresh
|
28
|
+
devices = usherm[:devSiteInfoSync][:devSiteInfoArray]
|
29
|
+
devices = devices.reject { |info| info[:idSite].to_i != args[1].to_i } if args.length == 2
|
30
|
+
(devices.map do |info|
|
31
|
+
"#{sprintf("%3d", info[:idDevSiteInfo]).to_s.light_blue} #{info[:serialNumber].red} -> Site ##{info[:idSite].to_s.bold}, #{info[:description]}"
|
32
|
+
end).join("\n")
|
33
|
+
else
|
34
|
+
description = args[3] rescue nil
|
35
|
+
usherm.update_device(args[1], description, args[2].to_i, "Added via netshell by #{`whoami`.chomp}@#{`hostname`.chomp}")
|
36
|
+
""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,245 @@
|
|
1
|
+
<<-EOS
|
2
|
+
|
3
|
+
net> site --add
|
4
|
+
|
5
|
+
What kind of site are we adding?
|
6
|
+
1) Development
|
7
|
+
2) Pulltab
|
8
|
+
3) Arcade
|
9
|
+
4) Production
|
10
|
+
|
11
|
+
Property name (e.g. "Casino del Sol")
|
12
|
+
> Casino del Sol
|
13
|
+
|
14
|
+
Geographic State
|
15
|
+
> AZ
|
16
|
+
> Arizona
|
17
|
+
|
18
|
+
Business day start (24-hour clock, e.g. 1300) # (actually supports H, HH, HMM, HH:MM)
|
19
|
+
> 12:35
|
20
|
+
> 0500
|
21
|
+
> 500
|
22
|
+
> 12
|
23
|
+
> 0
|
24
|
+
|
25
|
+
Host
|
26
|
+
> dev02.acres4.netx
|
27
|
+
That doesn't seem to be a valid usher host.
|
28
|
+
> dev02.acres4.net
|
29
|
+
|
30
|
+
Casino del Sol will accept the following CIDR blocks:
|
31
|
+
No CIDR blocks registered
|
32
|
+
|
33
|
+
You can A)dd or D)elete CIDR blocks, or C)ontinue with configuration
|
34
|
+
> A
|
35
|
+
|
36
|
+
CIDR block (e.g. 1.2.3.4/16):
|
37
|
+
> 1.2.3.4/16
|
38
|
+
Description for 1.2.3.4/16:
|
39
|
+
> Local wireless
|
40
|
+
|
41
|
+
Casino del Sol will accept the following CIDR blocks:
|
42
|
+
1.2.3.4/16 (Local wireless)
|
43
|
+
|
44
|
+
You can A)dd or D)elete CIDR blocks, or C)ontinue with configuration
|
45
|
+
> C
|
46
|
+
|
47
|
+
Casino del Sol will advertise the following servers:
|
48
|
+
1) Mercury (dev02.acres4.net)
|
49
|
+
2) Central (dev02.acres4.net)
|
50
|
+
3) Deployment (deployments.acres4.net)
|
51
|
+
C) Cancel
|
52
|
+
|
53
|
+
You can A)dd or D)elete servers, or C)ontinue with configuration
|
54
|
+
> D
|
55
|
+
|
56
|
+
Which server would you like Casino del Sol to stop advertising?
|
57
|
+
> 2
|
58
|
+
|
59
|
+
Casino del Sol will advertise the following servers:
|
60
|
+
1) Mercury (dev02.acres4.net)
|
61
|
+
2) Deployment (deployments.acres4.net)
|
62
|
+
|
63
|
+
You can A)dd or D)elete servers, or C)ontinue with configuration
|
64
|
+
> A
|
65
|
+
|
66
|
+
Which server would you like to advertise?
|
67
|
+
1) Central. Central Database Server.
|
68
|
+
2) Monitor.
|
69
|
+
3) Promo. Promotional contest server.
|
70
|
+
4) Switchboard. Switchboard server.
|
71
|
+
5) Kaicheck. Kaicheck diagnostic server.
|
72
|
+
6) Kaivoip. Voice server.
|
73
|
+
7) PickPromo.
|
74
|
+
8) Kailite.
|
75
|
+
C) Cancel
|
76
|
+
|
77
|
+
> 6
|
78
|
+
|
79
|
+
Which host would you like to use as a Kaivoip server?
|
80
|
+
1) dev02.acres4.net
|
81
|
+
2) example.com
|
82
|
+
C) Cancel
|
83
|
+
|
84
|
+
> 2
|
85
|
+
|
86
|
+
Casino del Sol will advertise the following servers:
|
87
|
+
1) Mercury (dev02.acres4.net)
|
88
|
+
2) Deployment (deployments.acres4.net)
|
89
|
+
3) Kaivoip (example.com)
|
90
|
+
|
91
|
+
You can A)dd or D)elete servers, or C)ontinue with configuration
|
92
|
+
> C
|
93
|
+
|
94
|
+
Casino del Sol has the following applications deployed:
|
95
|
+
No applications deployed
|
96
|
+
|
97
|
+
You can A)dd an application, D)elete an application, or C)ontinue with configuration
|
98
|
+
> A
|
99
|
+
|
100
|
+
What application would you like to deploy to Casino del Sol?
|
101
|
+
1) FrontLine
|
102
|
+
2) Supervisor
|
103
|
+
3) Kaicheck
|
104
|
+
...
|
105
|
+
> 3
|
106
|
+
|
107
|
+
Here are recent versions of Kaicheck:
|
108
|
+
1) [rc/lima] strangely stroked slug
|
109
|
+
2) [rc/juliet] gently torched dog
|
110
|
+
...
|
111
|
+
|
112
|
+
Enter the number of the build you want to deploy, or the name of another build if you know it:
|
113
|
+
> unsettlingly aroused llama
|
114
|
+
|
115
|
+
There doesn't seem to a build named that for Front Line.
|
116
|
+
> 2
|
117
|
+
|
118
|
+
Casino del Sol has the following applications deployed:
|
119
|
+
1) Supervisor (rc/juliet): gently torched dog
|
120
|
+
2) FrontLine (rc/juliet): gently torched dog
|
121
|
+
|
122
|
+
You can A)dd an application, D)elete an application, or C)ontinue with configuration
|
123
|
+
> C
|
124
|
+
|
125
|
+
CONGRATULATIONS!
|
126
|
+
You've finished defining a new site. Here's what we've wound up with:
|
127
|
+
|
128
|
+
Production site
|
129
|
+
example ("example")
|
130
|
+
Business day start: 02:00, US/Nevada
|
131
|
+
Base host: ip-10-1-0-24.acres4.net
|
132
|
+
|
133
|
+
CIDR blocks:
|
134
|
+
1.2.3.4/16 Local wifi
|
135
|
+
|
136
|
+
Advertised servers:
|
137
|
+
Mercury dev02.acres4.net
|
138
|
+
Deployment deployments.acres4.net
|
139
|
+
Kaivoip example.com
|
140
|
+
|
141
|
+
Applications:
|
142
|
+
FrontLine [rc/juliet] gently stroked dog
|
143
|
+
Supervisor [rc/juliet] gently stroked dog
|
144
|
+
|
145
|
+
Are these settings correct? [y/n]
|
146
|
+
>
|
147
|
+
Are these settings correct? [y/n]
|
148
|
+
> n
|
149
|
+
|
150
|
+
Pick a section to edit:
|
151
|
+
1) Basic site info
|
152
|
+
2) CIDR blocks
|
153
|
+
3) Advertised servers
|
154
|
+
4) Applications
|
155
|
+
C) Cancel
|
156
|
+
|
157
|
+
> C
|
158
|
+
|
159
|
+
CONGRATULATIONS!
|
160
|
+
You've finished defining a new site. Here's what we've wound up with:
|
161
|
+
|
162
|
+
Production site
|
163
|
+
casino-del-sol ("Casino del Sol")
|
164
|
+
Business day start: 04:00, US/Arizona
|
165
|
+
Base host: dev02.acres4.net
|
166
|
+
|
167
|
+
CIDR blocks:
|
168
|
+
10.1.0.128/30 Home
|
169
|
+
|
170
|
+
Advertised servers:
|
171
|
+
Mercury dev02.acres4.net
|
172
|
+
Deployment deployments.acres4.net
|
173
|
+
|
174
|
+
Applications:
|
175
|
+
FrontLine [rc/juliet] gently stroked dog
|
176
|
+
Supervisor [rc/juliet] gently stroked dog
|
177
|
+
|
178
|
+
Are these settings correct? [y/n]
|
179
|
+
> y
|
180
|
+
|
181
|
+
Creating site record...
|
182
|
+
Updating CIDR preferences...
|
183
|
+
Updating advertised server preferences...
|
184
|
+
Publishing usher changes...
|
185
|
+
Deploying applications...
|
186
|
+
Done!
|
187
|
+
|
188
|
+
NEW SITE ISSUED: example, site #36, system #1234
|
189
|
+
|
190
|
+
EOS
|
191
|
+
|
192
|
+
category "Usher"
|
193
|
+
description "Add, update and delete sites in usher"
|
194
|
+
usage [
|
195
|
+
"add",
|
196
|
+
"edit site_id",
|
197
|
+
"delete site_id"
|
198
|
+
]
|
199
|
+
|
200
|
+
tab 0 do
|
201
|
+
["add", "edit", "delete"]
|
202
|
+
end
|
203
|
+
|
204
|
+
tab 1 do
|
205
|
+
usherm[:usherSystemId][:usherSites].map { |site| site[:idSite] } +
|
206
|
+
usherm[:usherSystemId][:usherSites].map { |site| site[:name] }
|
207
|
+
end
|
208
|
+
|
209
|
+
validate do
|
210
|
+
return show_error("must connect usherm first") if usherm.nil?
|
211
|
+
return false if args.length == 1
|
212
|
+
case args[1]
|
213
|
+
when "add"
|
214
|
+
args.length == 2
|
215
|
+
when "edit", "delete"
|
216
|
+
args.length == 3
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
run do
|
221
|
+
case args[1]
|
222
|
+
when "add"
|
223
|
+
prompt_add
|
224
|
+
when "edit"
|
225
|
+
when "delete"
|
226
|
+
end
|
227
|
+
|
228
|
+
""
|
229
|
+
end
|
230
|
+
|
231
|
+
###
|
232
|
+
|
233
|
+
def prompt_add
|
234
|
+
end
|
235
|
+
|
236
|
+
def prompt_edit
|
237
|
+
end
|
238
|
+
|
239
|
+
def prompt_delete
|
240
|
+
end
|
241
|
+
|
242
|
+
###
|
243
|
+
|
244
|
+
def prompt(basis={})
|
245
|
+
end
|