nagios_mklivestatus 0.0.3 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +221 -0
- data/RELEASE.rdoc +20 -0
- data/bin/nagmk-conf.yml +2 -0
- data/bin/nagmk-ruby +146 -0
- data/bin/nagmk-ruby-config +93 -0
- data/lib/nagios_mklivestatus/exception/query_exception.rb +9 -0
- data/lib/nagios_mklivestatus/exception/request_exception.rb +8 -0
- data/lib/nagios_mklivestatus/exception.rb +19 -0
- data/lib/nagios_mklivestatus/filter/and.rb +64 -0
- data/lib/nagios_mklivestatus/filter/attr.rb +57 -0
- data/lib/nagios_mklivestatus/filter/negate.rb +49 -0
- data/lib/nagios_mklivestatus/filter/or.rb +64 -0
- data/lib/nagios_mklivestatus/filter.rb +19 -0
- data/lib/nagios_mklivestatus/parser.rb +258 -0
- data/lib/nagios_mklivestatus/query.rb +115 -4
- data/lib/nagios_mklivestatus/query_helper.rb +274 -0
- data/lib/nagios_mklivestatus/request.rb +232 -0
- data/lib/nagios_mklivestatus/stats/and.rb +79 -0
- data/lib/nagios_mklivestatus/stats/attr.rb +107 -0
- data/lib/nagios_mklivestatus/stats/or.rb +81 -0
- data/lib/nagios_mklivestatus/stats.rb +17 -0
- data/lib/nagios_mklivestatus/wait/and.rb +65 -0
- data/lib/nagios_mklivestatus/wait/attr.rb +59 -0
- data/lib/nagios_mklivestatus/wait/negate.rb +49 -0
- data/lib/nagios_mklivestatus/wait/object.rb +29 -0
- data/lib/nagios_mklivestatus/wait/or.rb +64 -0
- data/lib/nagios_mklivestatus/wait/timeout.rb +30 -0
- data/lib/nagios_mklivestatus/wait/trigger.rb +31 -0
- data/lib/nagios_mklivestatus/wait.rb +32 -0
- data/lib/nagios_mklivestatus.rb +112 -115
- metadata +53 -44
- data/README +0 -21
@@ -0,0 +1,81 @@
|
|
1
|
+
# This class is used to make a logical "OR" operator between two stats expressions.
|
2
|
+
#
|
3
|
+
# If one of the stats expression is also an "OR",
|
4
|
+
# it takes all the expressions of the operator as its own.
|
5
|
+
#
|
6
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
7
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
8
|
+
# License:: General Public Licence
|
9
|
+
class Nagios::MkLiveStatus::Stats::Or < Nagios::MkLiveStatus::Stats
|
10
|
+
|
11
|
+
include Nagios::MkLiveStatus
|
12
|
+
|
13
|
+
#
|
14
|
+
# Create a new "OR" operator between left and right expressions.
|
15
|
+
#
|
16
|
+
# Those expressions must be of type Nagios::MkLiveStatus::Stats
|
17
|
+
#
|
18
|
+
def initialize(left_expr, right_expr)
|
19
|
+
if not left_expr.is_a? Nagios::MkLiveStatus::Stats or not right_expr.is_a? Nagios::MkLiveStatus::Stats
|
20
|
+
raise QueryException.new("The left and the right operand for an OR expression must be stats expressions.")
|
21
|
+
end
|
22
|
+
|
23
|
+
@expressions = Array.new
|
24
|
+
if left_expr.is_a? Nagios::MkLiveStatus::Filter::Or
|
25
|
+
left_expr.get_expressions.each do |expr|
|
26
|
+
@expressions.push expr
|
27
|
+
end
|
28
|
+
else
|
29
|
+
@expressions.push left_expr
|
30
|
+
end
|
31
|
+
|
32
|
+
if right_expr.is_a? Nagios::MkLiveStatus::Filter::Or
|
33
|
+
right_expr.get_expressions.each do |expr|
|
34
|
+
@expressions.push expr
|
35
|
+
end
|
36
|
+
else
|
37
|
+
@expressions.push right_expr
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return all the expressions under the "OR". It's used by
|
44
|
+
# the new method in order to get all "OR" expressions into the same object.
|
45
|
+
#
|
46
|
+
def get_expressions
|
47
|
+
return @expressions
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Convert the current "OR" expression into a nagios query string
|
52
|
+
# Stats: ...
|
53
|
+
# Stats: ...
|
54
|
+
# StatsOr: 2
|
55
|
+
#
|
56
|
+
def to_s
|
57
|
+
or_arr = []
|
58
|
+
@expressions.each do |expr|
|
59
|
+
or_arr.push expr.to_s
|
60
|
+
end
|
61
|
+
or_arr.push "StatsOr: #{@expressions.length}"
|
62
|
+
return or_arr.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
# transform predicate to column name
|
66
|
+
# "left or right" with brackets if children
|
67
|
+
def to_column_name(has_parent=false)
|
68
|
+
or_arr = []
|
69
|
+
@expressions.each do |expr|
|
70
|
+
or_arr.push expr.to_column_name(true)
|
71
|
+
end
|
72
|
+
|
73
|
+
column_name = or_arr.join(" or ")
|
74
|
+
|
75
|
+
if has_parent
|
76
|
+
column_name = "( "+column_name+" )"
|
77
|
+
end
|
78
|
+
|
79
|
+
return column_name
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This class is used to agregate all stats class into one module.
|
2
|
+
#
|
3
|
+
# It also provides the following stats expressions:
|
4
|
+
# * Nagios::MkLiveStatus::Stats::Attr : standard attribute or field stats
|
5
|
+
# * Nagios::MkLiveStatus::Stats::And : "AND" operator between two stats expressions
|
6
|
+
# * Nagios::MkLiveStatus::Stats::Or : "OR" operator between two stats expressions
|
7
|
+
#
|
8
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
9
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
10
|
+
# License:: General Public Licence
|
11
|
+
class Nagios::MkLiveStatus::Stats
|
12
|
+
|
13
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "attr")
|
14
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "and")
|
15
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "or")
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# This class is used to make a logical "AND" operator between two wait expressions.
|
2
|
+
#
|
3
|
+
# If one of the wait expression is also an "AND",
|
4
|
+
# it takes all the expressions of the operator as its own.
|
5
|
+
#
|
6
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
7
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
8
|
+
# License:: General Public Licence
|
9
|
+
class Nagios::MkLiveStatus::Wait::And < Nagios::MkLiveStatus::Wait
|
10
|
+
|
11
|
+
include Nagios::MkLiveStatus
|
12
|
+
|
13
|
+
#
|
14
|
+
# Create a new "AND" operator between left and right expressions.
|
15
|
+
#
|
16
|
+
# Those expressions must be of type Nagios::MkLiveStatus::Wait
|
17
|
+
#
|
18
|
+
def initialize(left_expr, right_expr)
|
19
|
+
if not check_valid_condition(left_expr) or not check_valid_condition(right_expr)
|
20
|
+
raise QueryException.new("The left and the right operand for an OR expression must be valid wait conditions.")
|
21
|
+
end
|
22
|
+
|
23
|
+
@expressions = Array.new
|
24
|
+
if left_expr.is_a? Nagios::MkLiveStatus::Wait::And
|
25
|
+
left_expr.get_expressions.each do |expr|
|
26
|
+
@expressions.push expr
|
27
|
+
end
|
28
|
+
else
|
29
|
+
@expressions.push left_expr
|
30
|
+
end
|
31
|
+
|
32
|
+
if right_expr.is_a? Nagios::MkLiveStatus::Wait::And
|
33
|
+
right_expr.get_expressions.each do |expr|
|
34
|
+
@expressions.push expr
|
35
|
+
end
|
36
|
+
else
|
37
|
+
@expressions.push right_expr
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return all the expressions under the "AND". It's used by
|
44
|
+
# the new method in order to get all "AND" expressions into the same object.
|
45
|
+
#
|
46
|
+
def get_expressions
|
47
|
+
return @expressions
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Convert the current "AND" expression into a nagios query string
|
52
|
+
# WaitCondition: ...
|
53
|
+
# WaitCondition: ...
|
54
|
+
# WaitConditionAnd: 2
|
55
|
+
#
|
56
|
+
def to_s
|
57
|
+
and_arr = []
|
58
|
+
@expressions.each do |expr|
|
59
|
+
and_arr.push expr.to_s
|
60
|
+
end
|
61
|
+
and_arr.push "WaitConditionAnd: #{@expressions.length}"
|
62
|
+
return and_arr.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# This class symbolise a wait condition unit. This unit represents a small wait condition predicate like, in the nagios query, this :
|
2
|
+
# WaitCondition: host_name = name
|
3
|
+
#
|
4
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
5
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
6
|
+
# License:: General Public Licence
|
7
|
+
class Nagios::MkLiveStatus::Wait::Attr < Nagios::MkLiveStatus::Wait
|
8
|
+
|
9
|
+
include Nagios::MkLiveStatus
|
10
|
+
include Nagios::MkLiveStatus::QueryHelper::Comparator
|
11
|
+
|
12
|
+
#
|
13
|
+
# Create the unit predicate with the column name, the operator use to compare, and the value
|
14
|
+
# [attr_name] name of the column
|
15
|
+
# [attr_comp] operator, one of the constant of the class
|
16
|
+
# [attr_value] the value to compare to
|
17
|
+
#
|
18
|
+
def initialize (attr_name, attr_comp, attr_value)
|
19
|
+
|
20
|
+
list_comparator = get_all_comparators
|
21
|
+
|
22
|
+
if attr_name == nil or attr_name.empty?
|
23
|
+
raise QueryException.new("The name of the attribute must be set in order to create the wait condition")
|
24
|
+
else
|
25
|
+
@attr_name = attr_name
|
26
|
+
end
|
27
|
+
|
28
|
+
if list_comparator.index(attr_comp) == nil
|
29
|
+
raise QueryException.new("The comparator \"#{attr_comp}\" is not recognized.\n Please use one of : #{list_comparator.join(", ")}")
|
30
|
+
else
|
31
|
+
@attr_comp = attr_comp
|
32
|
+
end
|
33
|
+
|
34
|
+
@attr_value = attr_value
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Convert the Wait class to the nagios query string.
|
39
|
+
#
|
40
|
+
# Use the parameters to create a string corresponding to:
|
41
|
+
# WaitCondition: name comp value
|
42
|
+
#
|
43
|
+
def to_s
|
44
|
+
if @attr_name == nil or @attr_name.empty?
|
45
|
+
raise QueryException.new("The wait condition cannot be converted into string because the name of the attribute is not set.")
|
46
|
+
end
|
47
|
+
|
48
|
+
if @attr_comp == nil or @attr_comp.empty?
|
49
|
+
raise QueryException.new("The wait condition cannot be converted into string because the comparator of the attribute is not set.")
|
50
|
+
end
|
51
|
+
|
52
|
+
if @attr_value == nil or @attr_value.empty?
|
53
|
+
return "WaitCondition: "+@attr_name+" "+@attr_comp
|
54
|
+
end
|
55
|
+
|
56
|
+
return "WaitCondition: "+@attr_name+" "+@attr_comp+" "+@attr_value;
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This class is used to make a logical "NOT" operator for the expression.
|
2
|
+
#
|
3
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
4
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
5
|
+
# License:: General Public Licence
|
6
|
+
class Nagios::MkLiveStatus::Wait::Negate < Nagios::MkLiveStatus::Wait
|
7
|
+
|
8
|
+
include Nagios::MkLiveStatus
|
9
|
+
|
10
|
+
#
|
11
|
+
# Create a new "Not" operator to the expression.
|
12
|
+
#
|
13
|
+
# Those expressions must be of type Nagios::MkLiveStatus::Wait
|
14
|
+
#
|
15
|
+
def initialize(expr)
|
16
|
+
if not check_valid_condition expr
|
17
|
+
raise QueryException.new("The operand for a NEGATE expression must be one valid wait condition.")
|
18
|
+
end
|
19
|
+
|
20
|
+
@expression = expr
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Return the expression under the "Negate". It's used by
|
26
|
+
# the to_s method in order to remove the overflow of Negate expression.
|
27
|
+
#
|
28
|
+
def get_expression
|
29
|
+
return @expression
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Convert the current "Negate" expression into a nagios query string.
|
34
|
+
#
|
35
|
+
# If the sub expression is also a Negate, it returns the sub-sub expression without negating it.
|
36
|
+
# WaitCondition: ...
|
37
|
+
# WaitConditionNegate:
|
38
|
+
#
|
39
|
+
def to_s
|
40
|
+
if @expression.is_a? Nagios::MkLiveStatus::Wait::Negate
|
41
|
+
return @expression.get_expression.to_s
|
42
|
+
else
|
43
|
+
negate_arr = []
|
44
|
+
negate_arr.push @expression.to_s
|
45
|
+
negate_arr.push "WaitConditionNegate: "
|
46
|
+
return negate_arr.join("\n")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# This class is used to make a wait object.
|
2
|
+
#
|
3
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
4
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
5
|
+
# License:: General Public Licence
|
6
|
+
class Nagios::MkLiveStatus::Wait::Object < Nagios::MkLiveStatus::Wait
|
7
|
+
|
8
|
+
include Nagios::MkLiveStatus
|
9
|
+
|
10
|
+
#
|
11
|
+
# Create a new wait object expression.
|
12
|
+
#
|
13
|
+
def initialize(name)
|
14
|
+
if not name
|
15
|
+
raise QueryException.new("The object value must be set for the wait operation.")
|
16
|
+
end
|
17
|
+
|
18
|
+
@name = name
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Convert the current object expression into a nagios query string.
|
24
|
+
# WaitObject: ...
|
25
|
+
#
|
26
|
+
def to_s
|
27
|
+
return "WaitObject: "+@name
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# This class is used to make a logical "OR" operator between two wait condition expressions.
|
2
|
+
#
|
3
|
+
# If one of the wait condition expression is also an "OR",
|
4
|
+
# it takes all the expressions of the operator as its own.
|
5
|
+
#
|
6
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
7
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
8
|
+
# License:: General Public Licence
|
9
|
+
class Nagios::MkLiveStatus::Wait::Or < Nagios::MkLiveStatus::Wait
|
10
|
+
|
11
|
+
include Nagios::MkLiveStatus
|
12
|
+
|
13
|
+
#
|
14
|
+
# Create a new "OR" operator between left and right expressions.
|
15
|
+
#
|
16
|
+
# Those expressions must be of type Nagios::MkLiveStatus::Wait
|
17
|
+
#
|
18
|
+
def initialize(left_expr, right_expr)
|
19
|
+
if not check_valid_condition(left_expr) or not check_valid_condition(right_expr)
|
20
|
+
raise QueryException.new("The left and the right operand for an OR expression must be valid wait conditions.")
|
21
|
+
end
|
22
|
+
|
23
|
+
@expressions = Array.new
|
24
|
+
if left_expr.is_a? Nagios::MkLiveStatus::Wait::Or
|
25
|
+
left_expr.get_expressions.each do |expr|
|
26
|
+
@expressions.push expr
|
27
|
+
end
|
28
|
+
else
|
29
|
+
@expressions.push left_expr
|
30
|
+
end
|
31
|
+
|
32
|
+
if right_expr.is_a? Nagios::MkLiveStatus::Wait::Or
|
33
|
+
right_expr.get_expressions.each do |expr|
|
34
|
+
@expressions.push expr
|
35
|
+
end
|
36
|
+
else
|
37
|
+
@expressions.push right_expr
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return all the expressions under the "OR". It's used by
|
44
|
+
# the new method in order to get all "OR" expressions into the same object.
|
45
|
+
#
|
46
|
+
def get_expressions
|
47
|
+
return @expressions
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Convert the current "OR" expression into a nagios query string
|
52
|
+
# WaitCondition: ...
|
53
|
+
# WaitCondition: ...
|
54
|
+
# WaitConditionOr: 2
|
55
|
+
#
|
56
|
+
def to_s
|
57
|
+
or_arr = []
|
58
|
+
@expressions.each do |expr|
|
59
|
+
or_arr.push expr.to_s
|
60
|
+
end
|
61
|
+
or_arr.push "WaitConditionOr: #{@expressions.length}"
|
62
|
+
return or_arr.join("\n")
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This class is used to make a wait timeout.
|
2
|
+
#
|
3
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
4
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
5
|
+
# License:: General Public Licence
|
6
|
+
class Nagios::MkLiveStatus::Wait::Timeout < Nagios::MkLiveStatus::Wait
|
7
|
+
|
8
|
+
include Nagios::MkLiveStatus
|
9
|
+
|
10
|
+
#
|
11
|
+
# Create a new wait timeout expression.
|
12
|
+
# _Timeout in millisecond_
|
13
|
+
#
|
14
|
+
def initialize(timeout)
|
15
|
+
if not timeout
|
16
|
+
raise QueryException.new("The timeout must be set for the wait operation.")
|
17
|
+
end
|
18
|
+
|
19
|
+
@timeout = timeout
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Convert the current timeout expression into a nagios query string.
|
25
|
+
# WaitTimeout: ...
|
26
|
+
#
|
27
|
+
def to_s
|
28
|
+
return "WaitTimeout: "+@timeout
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# This class is used to make a wait trigger.
|
2
|
+
#
|
3
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
4
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
5
|
+
# License:: General Public Licence
|
6
|
+
class Nagios::MkLiveStatus::Wait::Trigger < Nagios::MkLiveStatus::Wait
|
7
|
+
|
8
|
+
include Nagios::MkLiveStatus
|
9
|
+
include Nagios::MkLiveStatus::QueryHelper::Trigger
|
10
|
+
|
11
|
+
#
|
12
|
+
# Create a new wait trigger expression.
|
13
|
+
#
|
14
|
+
def initialize(trigger=ALL)
|
15
|
+
list_triggers = get_all_triggers
|
16
|
+
if not list_triggers.include? trigger
|
17
|
+
raise QueryException.new("The trigger value must be one of #{list_triggers.join(', ')}")
|
18
|
+
end
|
19
|
+
|
20
|
+
@trigger = trigger
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Convert the current trigger expression into a nagios query string.
|
26
|
+
# WaitTrigger: ...
|
27
|
+
#
|
28
|
+
def to_s
|
29
|
+
return "WaitTrigger: "+@trigger
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# This class is used to agregate all waits class into one module.
|
2
|
+
#
|
3
|
+
# It also provides the following wait expressions:
|
4
|
+
# * Nagios::MkLiveStatus::Wait::Attr : standard attribute or field wait condition
|
5
|
+
# * Nagios::MkLiveStatus::Wait::And : "AND" operator between two wait conditions expressions
|
6
|
+
# * Nagios::MkLiveStatus::Wait::Or : "OR" operator between two wait conditions expressions
|
7
|
+
# * Nagios::MkLiveStatus::Wait::Negate : "NOT" operator for the last wait condition expressions
|
8
|
+
# * Nagios::MkLiveStatus::Wait::Object : symbolize the wait object
|
9
|
+
# * Nagios::MkLiveStatus::Wait::Trigger : wait trigger
|
10
|
+
# * Nagios::MkLiveStatus::Wait::Timeout : timeout of the wait
|
11
|
+
#
|
12
|
+
# Author:: Esco-lan Team (mailto:team@esco-lan.org)
|
13
|
+
# Copyright:: Copyright (c) 2012 GIP RECIA
|
14
|
+
# License:: General Public Licence
|
15
|
+
class Nagios::MkLiveStatus::Wait
|
16
|
+
|
17
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "attr")
|
18
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "and")
|
19
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "or")
|
20
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "negate")
|
21
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "trigger")
|
22
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "object")
|
23
|
+
require File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "timeout")
|
24
|
+
|
25
|
+
protected
|
26
|
+
#
|
27
|
+
# Check if the expression is a valid wait condition (WaitCondition, WaitConditionAnd, WaitConditionOr)
|
28
|
+
def check_valid_condition(expression)
|
29
|
+
expression.is_a? Nagios::MkLiveStatus::Wait::And or expression.is_a? Nagios::MkLiveStatus::Wait::Or or expression.is_a? Nagios::MkLiveStatus::Wait::Attr
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|