prometheus-splash 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d510e4761e365c1ee36881fb1a3a4a99a7dbe7965958841497cdcaaadfb0c1b3
4
- data.tar.gz: 4f01f486135696ef0142d42362379e59868b1265ce367b3e3aac9853fcc48336
3
+ metadata.gz: 5fd95d116c0f265b310c0ea710e909ab4022a5920c3c234524f2a1dcf9d21d0e
4
+ data.tar.gz: e21840114c3ea30be45b3766a14f00991b2a6629a44084ff6898ae39d88090c6
5
5
  SHA512:
6
- metadata.gz: 8b5c84b54b2098f9b027408ab8419fb19964feb1056607d090802acc793c2ccd6a9b98c1c8c2ca91334ccc8a36de88c1bf6cd674b6f5ef9df33a40debbfe84f5
7
- data.tar.gz: 1d93b819d8a9592495271a24bdc3e69e63a15489f5885faa729a8e42428a68dada73748ea8440c1338625a36c89d84a260e3bc9cdafa8fb869747864edc001f4
6
+ metadata.gz: ae5a2ed4a5100284605b7688e73f3fb59d008a7be9ce6e4050bfc5b9656663e4c2bb72f24f962b98544702a2bf0f2d889f6bd757a12ecb22c52a085cb70857b3
7
+ data.tar.gz: f9cf202cb9d0818e164fb35c705ab1593ae77e6ce28d06dc18d095d6e7c8c46cb45854f8bad0a661e0edba8f145acbc850ea5163e734b54094cfa50d4db5836b
@@ -81,3 +81,34 @@
81
81
  * quiet mode + no-colors and no-emoji #5
82
82
  * correlation id in log for daemon #15
83
83
  * systemd Splashd service installation #32
84
+
85
+
86
+ ## V 0.5.1 2020/04/17
87
+
88
+ ### CHANGES
89
+
90
+ * short Alias for commands without --no-[xxxx] #38
91
+ * REFACTO : namespaces
92
+ * Splash::Commands
93
+ * Splash::Log
94
+ * Splash::Daemon
95
+ * Splash::Daemon::Orchestrator
96
+
97
+
98
+ ### FEATURES
99
+
100
+ * flush backend arg in config #41
101
+ * adding global --debug flag
102
+ * adding splash Daemon metrics #25
103
+
104
+ ### DOC
105
+
106
+ * default value of mon scheduling 20s => 1m in ansible splash.yml
107
+
108
+
109
+ ### FIX
110
+
111
+ * Ansible Splash role handler error
112
+ * Ansible Splash role logrotate copytruncate for splash logs
113
+ * Prometheus Registry mismatch=> cumulative metrics on each groups #42
114
+ * logger Dual level conservation #43
@@ -34,6 +34,8 @@
34
34
  :daemon:
35
35
  :logmon_scheduling:
36
36
  :every: 20s
37
+ :metrics_scheduling:
38
+ :every: 20s
37
39
  :process_name: "Splash : daemon."
38
40
  :paths:
39
41
  :pid_path: /var/run/splash
@@ -36,6 +36,10 @@ module Splash
36
36
  return ::File.exist?("#{@path}/#{suffix_trace(options[:key])}")
37
37
  end
38
38
 
39
+ def flush
40
+ Dir.glob("#{@path}/*.trace").each { |file| ::File.delete(file)}
41
+ end
42
+
39
43
  private
40
44
  def suffix_trace(astring)
41
45
  return "#{astring}.trace"
@@ -9,7 +9,7 @@ module Splash
9
9
  conf = { :host => @config[:host], :port => @config[:port], :db => @config[:base].to_i}
10
10
  conf[:password] = @config[:auth] if @config[:auth]
11
11
  @store = ::Redis.new conf
12
- @redis_cli_cmd = `which redis-cli`
12
+ #@redis_cli_cmd = `which redis-cli`
13
13
  @store.auth(@config[:auth]) if @config[:auth]
14
14
  end
15
15
 
@@ -37,8 +37,8 @@ module Splash
37
37
  end
38
38
 
39
39
  def flush
40
- `#{@redis_cli_cmd} -n 3 flushdb`
41
- # @@store.flushdb
40
+ #`#{@redis_cli_cmd} -n #{@config[:base]} flushdb`
41
+ @store.flushdb
42
42
  end
43
43
 
44
44
  def exist?(options)
@@ -11,14 +11,16 @@ class CLI < Thor
11
11
  super
12
12
  log = get_logger
13
13
  options[:colors.to_s]
14
+ log.level = :debug if options[:debug]
14
15
  log.emoji = options[:emoji.to_s]
15
16
  log.color = options[:colors.to_s]
17
+ log.debug "DEBUG activated" if options[:debug]
16
18
  end
17
19
 
18
20
  class_option :quiet, :desc => "Quiet mode, limit output to :fatal", :aliases => "-q", :type => :boolean
19
21
  class_option :emoji, :desc => "Display Emoji", :type => :boolean, :default => true
20
22
  class_option :colors, :desc => "Display colors", :type => :boolean, :default => true
21
-
23
+ class_option :debug, :desc => "Set log level to :debug", :aliases => "-d", :type => :boolean
22
24
 
23
25
 
24
26
  include CLISplash
@@ -9,6 +9,7 @@ module CLISplash
9
9
  include Splash::Transports
10
10
  include Splash::Templates
11
11
  include Splash::Loggers
12
+ include Splash::Commands
12
13
 
13
14
  desc "execute NAME", "run for command/sequence or ack result"
14
15
  long_desc <<-LONGDESC
@@ -21,10 +22,10 @@ module CLISplash
21
22
  with --hostname, execute on an other Splash daemon node
22
23
  LONGDESC
23
24
  option :trace, :type => :boolean, :default => true
24
- option :ack, :type => :boolean, negate: false
25
+ option :ack, :type => :boolean, negate: false, :aliases => "-a"
25
26
  option :notify, :type => :boolean, :default => true
26
27
  option :callback, :type => :boolean, :default => true
27
- option :hostname, :type => :string
28
+ option :hostname, :type => :string, :aliases => "-H"
28
29
  def execute(name)
29
30
  log = get_logger
30
31
  log.level = :fatal if options[:quiet]
@@ -60,7 +61,7 @@ module CLISplash
60
61
  res[:more] = "Remote command : :execute_command Scheduled"
61
62
  splash_exit res
62
63
  else
63
- command = Splash::CommandWrapper::new(name)
64
+ command = CommandWrapper::new(name)
64
65
  if options[:ack] then
65
66
  splash_exit command.ack
66
67
  end
@@ -83,7 +84,7 @@ module CLISplash
83
84
  WARNING : scheduling by CLI are not percisted, so use it only for specifics cases.\n
84
85
  NOTES : Scheduling, force trace, notifying and callback.
85
86
  LONGDESC
86
- option :hostname, :type => :string, :default => Socket.gethostname
87
+ option :hostname, :type => :string, :default => Socket.gethostname, :aliases => "-H"
87
88
  option :at, :type => :string
88
89
  option :in, :type => :string
89
90
  def schedule(name)
@@ -121,7 +122,7 @@ module CLISplash
121
122
  Show commands sequence tree\n
122
123
  with --hostname, ask other Splash daemon via transport\n
123
124
  LONGDESC
124
- option :hostname, :type => :string
125
+ option :hostname, :type => :string, :aliases => "-H"
125
126
  def treeview(command)
126
127
  depht = 0
127
128
  log = get_logger
@@ -169,8 +170,8 @@ module CLISplash
169
170
  with --detail, show command details\n
170
171
  with --hostname, ask other Splash daemon via transport\n
171
172
  LONGDESC
172
- option :detail, :type => :boolean
173
- option :hostname, :type => :string
173
+ option :detail, :type => :boolean, :aliases => "-D"
174
+ option :hostname, :type => :string, :aliases => "-H"
174
175
  def list
175
176
  log = get_logger
176
177
  list = {}
@@ -218,7 +219,7 @@ module CLISplash
218
219
  Show specific configured command COMMAND\n
219
220
  with --hostname <HOSTNAME>, an other Splash monitored server (only with Redis backend configured)
220
221
  LONGDESC
221
- option :hostname, :type => :string
222
+ option :hostname, :type => :string, :aliases => "-H"
222
223
  def show(command)
223
224
  log = get_logger
224
225
  list = {}
@@ -264,7 +265,7 @@ module CLISplash
264
265
  Show last running result for specific configured command COMMAND\n
265
266
  with --hostname <HOSTNAME>, an other Splash monitored server (only with Redis backend configured)
266
267
  LONGDESC
267
- option :hostname, :type => :string
268
+ option :hostname, :type => :string, :aliases => "-H"
268
269
  def lastrun(command)
269
270
  log = get_logger
270
271
  backend = get_backend :execution_trace
@@ -307,10 +308,10 @@ module CLISplash
307
308
  with --detail, get major informations of each reports\n
308
309
  --all and --hostname are exclusives
309
310
  LONGDESC
310
- option :pattern, :type => :string
311
- option :hostname, :type => :string
312
- option :all, :type => :boolean, :negate => false
313
- option :detail, :type => :boolean
311
+ option :pattern, :type => :string, :aliases => "-p"
312
+ option :hostname, :type => :string, :aliases => "-H"
313
+ option :all, :type => :boolean, :negate => false, :aliases => "-A"
314
+ option :detail, :type => :boolean, :aliases => "-D"
314
315
  def getreportlist
315
316
  log = get_logger
316
317
  options[:hostname] = Socket.gethostname if options[:hostname] == 'hostname'
@@ -13,7 +13,7 @@ module CLISplash
13
13
  Setup installation fo Splash\n
14
14
  with --preserve, preserve from reinstallation of the config
15
15
  LONGDESC
16
- option :preserve, :type => :boolean
16
+ option :preserve, :type => :boolean, :aliases => "-P"
17
17
  def setup
18
18
  acase = run_as_root :setupsplash, options
19
19
  splash_exit acase
@@ -40,6 +40,12 @@ module CLISplash
40
40
  splash_exit acase
41
41
  end
42
42
 
43
+ desc "flushbackend", "Flush configured backend"
44
+ def flushbackend
45
+ acase = run_as_root :flush_backend
46
+ splash_exit acase
47
+ end
48
+
43
49
 
44
50
  end
45
51
 
@@ -2,13 +2,13 @@
2
2
  module CLISplash
3
3
 
4
4
  class CLIController < Thor
5
- include Splash::LogsMonitor::DaemonController
5
+ include Splash::Daemon::Controller
6
6
  include Splash::Transports
7
7
  include Splash::Exiter
8
8
  include Splash::Loggers
9
9
 
10
10
 
11
- option :foreground, :type => :boolean
11
+ option :foreground, :type => :boolean, :aliases => "-F"
12
12
  option :purge, :type => :boolean, default: true
13
13
  option :scheduling, :type => :boolean, default: true
14
14
  long_desc <<-LONGDESC
@@ -4,12 +4,13 @@ module CLISplash
4
4
  class Logs < Thor
5
5
  include Splash::Config
6
6
  include Splash::Exiter
7
+ include Splash::Logs
7
8
 
8
9
 
9
10
  desc "analyse", "analyze logs in config"
10
11
  def analyse
11
12
  log = get_logger
12
- results = Splash::LogScanner::new
13
+ results = LogScanner::new
13
14
  res = results.analyse
14
15
  log.info "SPlash Configured logs status :"
15
16
  full_status = true
@@ -42,7 +43,7 @@ module CLISplash
42
43
  def monitor
43
44
  log = get_logger
44
45
  log.level = :fatal if options[:quiet]
45
- result = Splash::LogScanner::new
46
+ result = LogScanner::new
46
47
  result.analyse
47
48
  splash_exit result.notify
48
49
 
@@ -67,7 +68,7 @@ module CLISplash
67
68
  Show configured logs monitoring\n
68
69
  with --detail, show logs monitor details
69
70
  LONGDESC
70
- option :detail, :type => :boolean
71
+ option :detail, :type => :boolean, :aliases => "-D"
71
72
  def list
72
73
  log = get_logger
73
74
  log.info "Splash configured log monitoring :"
@@ -1,146 +1,148 @@
1
1
  # coding: utf-8
2
2
  module Splash
3
- class CommandWrapper
4
- include Splash::Templates
5
- include Splash::Config
6
- include Splash::Helpers
7
- include Splash::Backends
8
- include Splash::Exiter
9
- include Splash::Transports
3
+ module Commands
4
+ class CommandWrapper
5
+ include Splash::Templates
6
+ include Splash::Config
7
+ include Splash::Helpers
8
+ include Splash::Backends
9
+ include Splash::Exiter
10
+ include Splash::Transports
10
11
 
11
12
 
12
- @@registry = Prometheus::Client.registry
13
- @@metric_exitcode = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
14
- @@metric_time = Prometheus::Client::Gauge.new(:exectime, docstring: 'SPLASH metric batch execution time')
15
- @@registry.register(@@metric_exitcode)
16
- @@registry.register(@@metric_time)
13
+ @@registry = Prometheus::Client::Registry::new
14
+ @@metric_exitcode = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
15
+ @@metric_time = Prometheus::Client::Gauge.new(:exectime, docstring: 'SPLASH metric batch execution time')
16
+ @@registry.register(@@metric_exitcode)
17
+ @@registry.register(@@metric_time)
17
18
 
18
- def initialize(name)
19
- @config = get_config
20
- @url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
21
- @name = name
22
- unless @config.commands.keys.include? @name.to_sym then
23
- splash_exit case: :not_found, more: "command #{@name} is not defined in configuration"
19
+ def initialize(name)
20
+ @config = get_config
21
+ @url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
22
+ @name = name
23
+ unless @config.commands.keys.include? @name.to_sym then
24
+ splash_exit case: :not_found, more: "command #{@name} is not defined in configuration"
25
+ end
24
26
  end
25
- end
26
27
 
27
- def ack
28
- get_logger.info "Sending ack for command : '#{@name}'"
29
- notify(0,0)
30
- end
28
+ def ack
29
+ get_logger.info "Sending ack for command : '#{@name}'"
30
+ notify(0,0)
31
+ end
31
32
 
32
- def notify(value,time)
33
- unless verify_service host: @config.prometheus_pushgateway_host ,port: @config.prometheus_pushgateway_port then
34
- return { :case => :service_dependence_missing, :more => "Prometheus Notification not send."}
33
+ def notify(value,time)
34
+ unless verify_service host: @config.prometheus_pushgateway_host ,port: @config.prometheus_pushgateway_port then
35
+ return { :case => :service_dependence_missing, :more => "Prometheus Notification not send."}
36
+ end
37
+ @@metric_exitcode.set(value)
38
+ @@metric_time.set(time)
39
+ hostname = Socket.gethostname
40
+ Prometheus::Client::Push.new(@name, hostname, @url).add(@@registry)
41
+ return { :case => :quiet_exit}
35
42
  end
36
- @@metric_exitcode.set(value)
37
- @@metric_time.set(time)
38
- hostname = Socket.gethostname
39
- Prometheus::Client::Push.new(@name, hostname, @url).add(@@registry)
40
- return { :case => :quiet_exit}
41
- end
42
43
 
43
44
 
44
- def call_and_notify(options)
45
- log = get_logger
46
- session = (options[:session])? options[:session] : get_session
47
- acase = { :case => :quiet_exit }
48
- exit_code = 0
49
- if @config.commands[@name.to_sym][:delegate_to] then
50
- return { :case => :options_incompatibility, :more => '--hostname forbidden with delagate commands'} if options[:hostname]
51
- log.send "Remote command : #{@name} execution delegate to : #{@config.commands[@name.to_sym][:delegate_to][:host]} as : #{@config.commands[@name.to_sym][:delegate_to][:remote_command]}", session
52
- begin
53
- transport = get_default_client
54
- if transport.class == Hash and transport.include? :case then
55
- return transport
56
- else
57
- res = transport.execute({ :verb => :execute_command,
58
- payload: {:name => @config.commands[@name.to_sym][:delegate_to][:remote_command].to_s},
59
- :return_to => "splash.#{Socket.gethostname}.return",
60
- :queue => "splash.#{@config.commands[@name.to_sym][:delegate_to][:host]}.input" })
61
- exit_code = res[:exit_code]
62
- log.receive "return with exitcode #{exit_code}", session
45
+ def call_and_notify(options)
46
+ log = get_logger
47
+ session = (options[:session])? options[:session] : get_session
48
+ acase = { :case => :quiet_exit }
49
+ exit_code = 0
50
+ if @config.commands[@name.to_sym][:delegate_to] then
51
+ return { :case => :options_incompatibility, :more => '--hostname forbidden with delagate commands'} if options[:hostname]
52
+ log.send "Remote command : #{@name} execution delegate to : #{@config.commands[@name.to_sym][:delegate_to][:host]} as : #{@config.commands[@name.to_sym][:delegate_to][:remote_command]}", session
53
+ begin
54
+ transport = get_default_client
55
+ if transport.class == Hash and transport.include? :case then
56
+ return transport
57
+ else
58
+ res = transport.execute({ :verb => :execute_command,
59
+ payload: {:name => @config.commands[@name.to_sym][:delegate_to][:remote_command].to_s},
60
+ :return_to => "splash.#{Socket.gethostname}.return",
61
+ :queue => "splash.#{@config.commands[@name.to_sym][:delegate_to][:host]}.input" })
62
+ exit_code = res[:exit_code]
63
+ log.receive "return with exitcode #{exit_code}", session
63
64
 
65
+ end
64
66
  end
65
- end
66
- else
67
- log.info "Executing command : '#{@name}' ", session
68
- start = Time.now
69
- start_date = DateTime.now.to_s
70
- unless options[:trace] then
71
- log.item "Traceless execution", session
72
- if @config.commands[@name.to_sym][:user] then
73
- log.item "Execute with user : #{@config.commands[@name.to_sym][:user]}.", session
74
- system("sudo -u #{@config.commands[@name.to_sym][:user]} #{@config.commands[@name.to_sym][:command]} > /dev/null 2>&1")
67
+ else
68
+ log.info "Executing command : '#{@name}' ", session
69
+ start = Time.now
70
+ start_date = DateTime.now.to_s
71
+ unless options[:trace] then
72
+ log.item "Traceless execution", session
73
+ if @config.commands[@name.to_sym][:user] then
74
+ log.item "Execute with user : #{@config.commands[@name.to_sym][:user]}.", session
75
+ system("sudo -u #{@config.commands[@name.to_sym][:user]} #{@config.commands[@name.to_sym][:command]} > /dev/null 2>&1")
76
+ else
77
+ system("#{@config.commands[@name.to_sym][:command]} > /dev/null 2>&1")
78
+ end
79
+ time = Time.now - start
80
+ exit_code = $?.exitstatus
75
81
  else
76
- system("#{@config.commands[@name.to_sym][:command]} > /dev/null 2>&1")
82
+ log.item "Tracefull execution", session
83
+ if @config.commands[@name.to_sym][:user] then
84
+ log.item "Execute with user : #{@config.commands[@name.to_sym][:user]}.", session
85
+ stdout, stderr, status = Open3.capture3("sudo -u #{@config.commands[@name.to_sym][:user]} #{@config.commands[@name.to_sym][:command]}")
86
+ else
87
+ stdout, stderr, status = Open3.capture3(@config.commands[@name.to_sym][:command])
88
+ end
89
+ time = Time.now - start
90
+ tp = Template::new(
91
+ list_token: @config.execution_template_tokens,
92
+ template_file: @config.execution_template_path)
93
+ data = Hash::new
94
+ data[:start_date] = start_date
95
+ data[:end_date] = DateTime.now.to_s
96
+ data[:cmd_name] = @name
97
+ data[:cmd_line] = @config.commands[@name.to_sym][:command]
98
+ data[:desc] = @config.commands[@name.to_sym][:desc]
99
+ data[:status] = status.to_s
100
+ data[:stdout] = stdout
101
+ data[:stderr] = stderr
102
+ data[:exec_time] = time.to_s
103
+ backend = get_backend :execution_trace
104
+ key = @name
105
+
106
+ backend.put key: key, value: data.to_yaml
107
+ exit_code = status.exitstatus
77
108
  end
78
- time = Time.now - start
79
- exit_code = $?.exitstatus
80
- else
81
- log.item "Tracefull execution", session
82
- if @config.commands[@name.to_sym][:user] then
83
- log.item "Execute with user : #{@config.commands[@name.to_sym][:user]}.", session
84
- stdout, stderr, status = Open3.capture3("sudo -u #{@config.commands[@name.to_sym][:user]} #{@config.commands[@name.to_sym][:command]}")
109
+ log.ok "Command executed", session
110
+ log.arrow "exitcode #{exit_code}", session
111
+ if options[:notify] then
112
+ acase = notify(exit_code,time.to_i)
113
+ get_logger.ok "Prometheus Gateway notified.",session
85
114
  else
86
- stdout, stderr, status = Open3.capture3(@config.commands[@name.to_sym][:command])
115
+ log.item "Without Prometheus notification", session
87
116
  end
88
- time = Time.now - start
89
- tp = Template::new(
90
- list_token: @config.execution_template_tokens,
91
- template_file: @config.execution_template_path)
92
- data = Hash::new
93
- data[:start_date] = start_date
94
- data[:end_date] = DateTime.now.to_s
95
- data[:cmd_name] = @name
96
- data[:cmd_line] = @config.commands[@name.to_sym][:command]
97
- data[:desc] = @config.commands[@name.to_sym][:desc]
98
- data[:status] = status.to_s
99
- data[:stdout] = stdout
100
- data[:stderr] = stderr
101
- data[:exec_time] = time.to_s
102
- backend = get_backend :execution_trace
103
- key = @name
104
-
105
- backend.put key: key, value: data.to_yaml
106
- exit_code = status.exitstatus
107
117
  end
108
- log.ok "Command executed", session
109
- log.arrow "exitcode #{exit_code}", session
110
- if options[:notify] then
111
- acase = notify(exit_code,time.to_i)
112
- get_logger.ok "Prometheus Gateway notified.",session
113
- else
114
- log.item "Without Prometheus notification", session
115
- end
116
- end
117
118
 
118
- if options[:callback] then
119
- on_failure = (@config.commands[@name.to_sym][:on_failure])? @config.commands[@name.to_sym][:on_failure] : false
120
- on_success = (@config.commands[@name.to_sym][:on_success])? @config.commands[@name.to_sym][:on_success] : false
121
- if on_failure and exit_code > 0 then
122
- log.item "On failure callback : #{on_failure}", session
123
- if @config.commands.keys.include? on_failure then
124
- @name = on_failure.to_s
125
- call_and_notify options
126
- else
127
- acase = { :case => :configuration_error , :more => "on_failure call error : #{on_failure} command inexistant."}
119
+ if options[:callback] then
120
+ on_failure = (@config.commands[@name.to_sym][:on_failure])? @config.commands[@name.to_sym][:on_failure] : false
121
+ on_success = (@config.commands[@name.to_sym][:on_success])? @config.commands[@name.to_sym][:on_success] : false
122
+ if on_failure and exit_code > 0 then
123
+ log.item "On failure callback : #{on_failure}", session
124
+ if @config.commands.keys.include? on_failure then
125
+ @name = on_failure.to_s
126
+ call_and_notify options
127
+ else
128
+ acase = { :case => :configuration_error , :more => "on_failure call error : #{on_failure} command inexistant."}
129
+ end
128
130
  end
129
- end
130
- if on_success and exit_code == 0 then
131
- log.item "On success callback : #{on_success}", session
132
- if @config.commands.keys.include? on_success then
133
- @name = on_success.to_s
134
- call_and_notify options
135
- else
136
- acase = { :case => :configuration_error , :more => "on_success call error : #{on_failure} command inexistant."}
131
+ if on_success and exit_code == 0 then
132
+ log.item "On success callback : #{on_success}", session
133
+ if @config.commands.keys.include? on_success then
134
+ @name = on_success.to_s
135
+ call_and_notify options
136
+ else
137
+ acase = { :case => :configuration_error , :more => "on_success call error : #{on_failure} command inexistant."}
138
+ end
137
139
  end
140
+ else
141
+ log.item "Without callbacks sequences", session
138
142
  end
139
- else
140
- log.item "Without callbacks sequences", session
143
+ acase[:exit_code] = exit_code
144
+ return acase
141
145
  end
142
- acase[:exit_code] = exit_code
143
- return acase
144
146
  end
145
147
  end
146
148
  end