oxidized 0.19.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/Dockerfile +17 -2
- data/Gemfile +0 -1
- data/Gemfile.lock +10 -9
- data/README.md +205 -10
- data/extra/auto-reload-config.runit +1 -1
- data/extra/oxidized.init +3 -3
- data/extra/update-ca-certificates.runit +7 -0
- data/lib/oxidized/config.rb +4 -2
- data/lib/oxidized/config/vars.rb +5 -1
- data/lib/oxidized/hook/exec.rb +1 -0
- data/lib/oxidized/hook/slackdiff.rb +34 -0
- data/lib/oxidized/input/ssh.rb +4 -1
- data/lib/oxidized/model/aireos.rb +1 -1
- data/lib/oxidized/model/airos.rb +9 -4
- data/lib/oxidized/model/alvarion.rb +3 -1
- data/lib/oxidized/model/aosw.rb +22 -6
- data/lib/oxidized/model/asa.rb +3 -2
- data/lib/oxidized/model/cisconga.rb +19 -0
- data/lib/oxidized/model/comware.rb +6 -0
- data/lib/oxidized/model/cumulus.rb +15 -3
- data/lib/oxidized/model/fabricos.rb +2 -1
- data/lib/oxidized/model/fiberdriver.rb +4 -0
- data/lib/oxidized/model/firewareos.rb +7 -1
- data/lib/oxidized/model/fortios.rb +15 -4
- data/lib/oxidized/model/ios.rb +83 -8
- data/lib/oxidized/model/ironware.rb +5 -6
- data/lib/oxidized/model/junos.rb +3 -0
- data/lib/oxidized/model/mlnxos.rb +5 -1
- data/lib/oxidized/model/netgear.rb +32 -0
- data/lib/oxidized/model/nxos.rb +14 -1
- data/lib/oxidized/model/oneos.rb +58 -0
- data/lib/oxidized/model/opengear.rb +2 -0
- data/lib/oxidized/model/pfsense.rb +3 -2
- data/lib/oxidized/model/powerconnect.rb +1 -0
- data/lib/oxidized/model/procurve.rb +8 -3
- data/lib/oxidized/model/quantaos.rb +1 -1
- data/lib/oxidized/model/routeros.rb +8 -0
- data/lib/oxidized/model/saos.rb +3 -1
- data/lib/oxidized/model/siklu.rb +19 -0
- data/lib/oxidized/model/timos.rb +16 -0
- data/lib/oxidized/model/tplink.rb +65 -0
- data/lib/oxidized/model/voltaire.rb +56 -0
- data/lib/oxidized/model/voss.rb +33 -0
- data/lib/oxidized/model/zhoneolt.rb +52 -0
- data/lib/oxidized/node.rb +39 -10
- data/lib/oxidized/nodes.rb +2 -1
- data/lib/oxidized/output/gitcrypt.rb +244 -0
- data/lib/oxidized/source/csv.rb +10 -1
- data/lib/oxidized/source/http.rb +24 -7
- data/lib/oxidized/version.rb +1 -1
- data/lib/oxidized/worker.rb +3 -2
- data/oxidized.gemspec +2 -1
- metadata +29 -4
@@ -30,10 +30,11 @@ class IronWare < Oxidized::Model
|
|
30
30
|
end
|
31
31
|
|
32
32
|
cmd 'show chassis' do |cfg|
|
33
|
-
cfg.encode!("UTF-8", :invalid => :replace) #sometimes ironware returns broken encoding
|
33
|
+
cfg.encode!("UTF-8", :invalid => :replace, :undef => :replace) #sometimes ironware returns broken encoding
|
34
34
|
cfg.gsub! /(^((.*)Current temp(.*))$)/, '' #remove unwanted lines current temperature
|
35
35
|
cfg.gsub! /Speed = [A-Z-]{2,6} \(\d{2,3}\%\)/, '' #remove unwanted lines Speed Fans
|
36
36
|
cfg.gsub! /current speed is [A-Z]{2,6} \(\d{2,3}\%\)/, ''
|
37
|
+
cfg.gsub! /([\[]*)1([\]]*)<->([\[]*)2([\]]*)(<->([\[]*)3([\]]*))*/, ''
|
37
38
|
cfg.gsub! /\d{2}\.\d deg-C/, 'XX.X deg-C'
|
38
39
|
if cfg.include? "TEMPERATURE"
|
39
40
|
sc = StringScanner.new cfg
|
@@ -66,23 +67,21 @@ class IronWare < Oxidized::Model
|
|
66
67
|
# match expected prompts on both older and newer
|
67
68
|
# versions of IronWare
|
68
69
|
username /^(Please Enter Login Name|Username):/
|
69
|
-
password /^(Please Enter )
|
70
|
+
password /^(Please Enter Password |Password):/
|
70
71
|
end
|
71
72
|
|
72
73
|
#handle pager with enable
|
73
74
|
cfg :telnet, :ssh do
|
74
75
|
if vars :enable
|
75
76
|
post_login do
|
76
|
-
send "enable\
|
77
|
+
send "enable\n"
|
77
78
|
cmd vars(:enable)
|
78
79
|
end
|
79
80
|
end
|
80
81
|
post_login ''
|
81
82
|
post_login 'skip-page-display'
|
82
83
|
post_login 'terminal length 0'
|
83
|
-
pre_logout
|
84
|
-
pre_logout 'exit'
|
85
|
-
pre_logout 'exit'
|
84
|
+
pre_logout "logout\nexit\nexit\n"
|
86
85
|
end
|
87
86
|
|
88
87
|
end
|
data/lib/oxidized/model/junos.rb
CHANGED
@@ -8,6 +8,7 @@ class JunOS < Oxidized::Model
|
|
8
8
|
|
9
9
|
cmd :all do |cfg|
|
10
10
|
cfg = cfg.lines.to_a[1..-2].join if screenscrape
|
11
|
+
cfg.gsub!(/ scale-subscriber (\s+)(\d+)/,' scale-subscriber <count>')
|
11
12
|
cfg.lines.map { |line| line.rstrip }.join("\n") + "\n"
|
12
13
|
end
|
13
14
|
|
@@ -36,6 +37,8 @@ class JunOS < Oxidized::Model
|
|
36
37
|
end
|
37
38
|
|
38
39
|
cmd('show chassis hardware') { |cfg| comment cfg }
|
40
|
+
cmd('show system license') { |cfg| comment cfg }
|
41
|
+
cmd('show system license keys') { |cfg| comment cfg }
|
39
42
|
|
40
43
|
cfg :telnet do
|
41
44
|
username(/^login:/)
|
@@ -13,6 +13,10 @@ class MLNXOS < Oxidized::Model
|
|
13
13
|
cfg.gsub! /\[\?1h=\r/, '' # Pager Handling
|
14
14
|
cfg.gsub! /\r\[K/,'' # Pager Handling
|
15
15
|
cfg.gsub! /\s/, '' # Linebreak Handling
|
16
|
+
cfg.gsub! /^CPU\ load\ averages\:\s.+/, '' # Omit constantly changing CPU info
|
17
|
+
cfg.gsub! /^System\ memory\:\s.+/, '' # Omit constantly changing memory info
|
18
|
+
cfg.gsub! /^Uptime\:\s.+/, '' # Omit constantly changing uptime info
|
19
|
+
cfg.gsub! /.+Generated\ at\s\d+.+/, '' # Omit constantly changing generation time info
|
16
20
|
cfg = cfg.lines.to_a[2..-3].join
|
17
21
|
end
|
18
22
|
|
@@ -38,6 +42,6 @@ class MLNXOS < Oxidized::Model
|
|
38
42
|
|
39
43
|
cfg :ssh do
|
40
44
|
password /^Password:\s*/
|
41
|
-
pre_logout
|
45
|
+
pre_logout "\nexit"
|
42
46
|
end
|
43
47
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Netgear < Oxidized::Model
|
2
|
+
|
3
|
+
comment '!'
|
4
|
+
prompt /^(\([\w-]+\)\s[#>])$/
|
5
|
+
|
6
|
+
cmd :secret do |cfg|
|
7
|
+
cfg.gsub!(/password (\S+)/, 'password <hidden>')
|
8
|
+
cfg
|
9
|
+
end
|
10
|
+
|
11
|
+
cfg :telnet, :ssh do
|
12
|
+
if vars :enable
|
13
|
+
post_login do
|
14
|
+
cmd 'enable'
|
15
|
+
# Interpret enable: true as meaning we won't be prompted for a password
|
16
|
+
unless vars(:enable).is_a? TrueClass
|
17
|
+
expect /[pP]assword:\s?$/
|
18
|
+
cmd vars(:enable) + "\n"
|
19
|
+
end
|
20
|
+
expect /^.+[#]$/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
post_login 'terminal length 0'
|
24
|
+
pre_logout 'exit'
|
25
|
+
pre_logout 'quit'
|
26
|
+
end
|
27
|
+
|
28
|
+
cmd 'show running-config' do |cfg|
|
29
|
+
cfg.gsub! /^(!.*Time).*$/, '\1'
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/oxidized/model/nxos.rb
CHANGED
@@ -3,6 +3,14 @@ class NXOS < Oxidized::Model
|
|
3
3
|
prompt /^(\r?[\w.@_()-]+[#]\s?)$/
|
4
4
|
comment '! '
|
5
5
|
|
6
|
+
cmd :secret do |cfg|
|
7
|
+
cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
|
8
|
+
cfg.gsub! /^(snmp-server user (\S+) (\S+) auth (\S+)) (\S+) (priv) (\S+)/, '\\1 <configuration removed> '
|
9
|
+
cfg.gsub! /^(username \S+ password \d) (\S+)/, '\\1 <secret hidden>'
|
10
|
+
cfg.gsub! /^(radius-server key).*/, '\\1 <secret hidden>'
|
11
|
+
cfg
|
12
|
+
end
|
13
|
+
|
6
14
|
cmd 'show version' do |cfg|
|
7
15
|
cfg = cfg.each_line.take_while { |line| not line.match(/uptime/i) }
|
8
16
|
comment cfg.join ""
|
@@ -16,8 +24,13 @@ class NXOS < Oxidized::Model
|
|
16
24
|
cfg.gsub! /^!Time:[^\n]*\n/, ''
|
17
25
|
end
|
18
26
|
|
19
|
-
cfg :ssh do
|
27
|
+
cfg :ssh, :telnet do
|
20
28
|
post_login 'terminal length 0'
|
21
29
|
pre_logout 'exit'
|
22
30
|
end
|
31
|
+
|
32
|
+
cfg :telnet do
|
33
|
+
username /^login:/
|
34
|
+
password /^Password:/
|
35
|
+
end
|
23
36
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class OneOS < Oxidized::Model
|
2
|
+
|
3
|
+
prompt /^([\w.@()-]+#\s?)$/
|
4
|
+
comment '! '
|
5
|
+
|
6
|
+
# example how to handle pager
|
7
|
+
#expect /^\s--More--\s+.*$/ do |data, re|
|
8
|
+
# send ' '
|
9
|
+
# data.sub re, ''
|
10
|
+
#end
|
11
|
+
|
12
|
+
# non-preferred way to handle additional PW prompt
|
13
|
+
#expect /^[\w.]+>$/ do |data|
|
14
|
+
# send "enable\n"
|
15
|
+
# send vars(:enable) + "\n"
|
16
|
+
# data
|
17
|
+
#end
|
18
|
+
|
19
|
+
cmd :all do |cfg|
|
20
|
+
#cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager
|
21
|
+
#cfg.gsub! /\cH+/, '' # example how to handle pager
|
22
|
+
cfg.each_line.to_a[1..-2].join
|
23
|
+
end
|
24
|
+
|
25
|
+
cmd :secret do |cfg|
|
26
|
+
cfg.gsub! /^(snmp set-read-community ").*+?(".*)$/, '\\1<secret hidden>\\2'
|
27
|
+
cfg
|
28
|
+
end
|
29
|
+
|
30
|
+
cmd 'show version' do |cfg|
|
31
|
+
comment cfg
|
32
|
+
end
|
33
|
+
|
34
|
+
cmd 'show running-config' do |cfg|
|
35
|
+
cfg = cfg.each_line.to_a[0..-1].join
|
36
|
+
cfg.gsub! /^Building configuration...\s*[^\n]*\n/, ''
|
37
|
+
cfg.gsub! /^Current configuration :\s*[^\n]*\n/, ''
|
38
|
+
cfg
|
39
|
+
end
|
40
|
+
|
41
|
+
cfg :telnet do
|
42
|
+
username /^Username:/
|
43
|
+
password /^Password:/
|
44
|
+
end
|
45
|
+
|
46
|
+
cfg :telnet, :ssh do
|
47
|
+
# preferred way to handle additional passwords
|
48
|
+
if vars :enable
|
49
|
+
post_login do
|
50
|
+
send "enable\n"
|
51
|
+
cmd vars(:enable)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
post_login 'term len 0'
|
55
|
+
pre_logout 'exit'
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -3,11 +3,12 @@ class PfSense < Oxidized::Model
|
|
3
3
|
# use other use than 'admin' user, 'admin' user cannot get ssh/exec. See issue #535
|
4
4
|
|
5
5
|
cmd :all do |cfg|
|
6
|
-
cfg.each_line.to_a[1..-
|
6
|
+
cfg.each_line.to_a[1..-1].join
|
7
7
|
end
|
8
8
|
|
9
9
|
cmd 'cat /cf/conf/config.xml' do |cfg|
|
10
|
-
cfg.gsub! /\s<revision>\s
|
10
|
+
cfg.gsub! /\s<revision>\s*<time>\d*<\/time>\s*.*\s*.*\s*<\/revision>/, ''
|
11
|
+
cfg.gsub! /\s<last_rule_upd_time>\d*<\/last_rule_upd_time>/, ''
|
11
12
|
cfg
|
12
13
|
end
|
13
14
|
|
@@ -1,11 +1,16 @@
|
|
1
1
|
class Procurve < Oxidized::Model
|
2
2
|
|
3
|
-
# some models start lines with \r
|
3
|
+
# some models start lines with \r
|
4
4
|
# previous command is repeated followed by "\eE", which sometimes ends up on last line
|
5
|
-
prompt /^\r?([\w
|
5
|
+
prompt /^\r?([\w.-]+# )$/
|
6
6
|
|
7
7
|
comment '! '
|
8
8
|
|
9
|
+
# replace next line control sequence with a new line
|
10
|
+
expect /(\e\[1M\e\[\??\d+(;\d+)*[A-Za-z]\e\[1L)|(\eE)/ do |data, re|
|
11
|
+
data.gsub re, "\n"
|
12
|
+
end
|
13
|
+
|
9
14
|
# replace all used vt100 control sequences
|
10
15
|
expect /\e\[\??\d+(;\d+)*[A-Za-z]/ do |data, re|
|
11
16
|
data.gsub re, ''
|
@@ -17,7 +22,7 @@ class Procurve < Oxidized::Model
|
|
17
22
|
end
|
18
23
|
|
19
24
|
cmd :all do |cfg|
|
20
|
-
cfg = cfg.each_line.to_a[1..-
|
25
|
+
cfg = cfg.each_line.to_a[1..-2].join
|
21
26
|
cfg = cfg.gsub /^\r/, ''
|
22
27
|
end
|
23
28
|
|
@@ -6,6 +6,10 @@ class RouterOS < Oxidized::Model
|
|
6
6
|
comment cfg
|
7
7
|
end
|
8
8
|
|
9
|
+
cmd '/system package update print' do |cfg|
|
10
|
+
comment cfg
|
11
|
+
end
|
12
|
+
|
9
13
|
cmd '/export' do |cfg|
|
10
14
|
cfg.gsub! /\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]/, '' # strip ANSI colours
|
11
15
|
cfg.gsub! /\\\r\n\s+/, '' # strip new line
|
@@ -18,6 +22,10 @@ class RouterOS < Oxidized::Model
|
|
18
22
|
password /^Password:/
|
19
23
|
end
|
20
24
|
|
25
|
+
cfg :telnet, :ssh do
|
26
|
+
pre_logout 'quit'
|
27
|
+
end
|
28
|
+
|
21
29
|
cfg :ssh do
|
22
30
|
exec true
|
23
31
|
end
|
data/lib/oxidized/model/saos.rb
CHANGED
@@ -2,7 +2,7 @@ class SAOS < Oxidized::Model
|
|
2
2
|
|
3
3
|
# Ciena SAOS switch
|
4
4
|
# used for 6.x devices
|
5
|
-
|
5
|
+
|
6
6
|
comment '! '
|
7
7
|
|
8
8
|
cmd :all do |cfg|
|
@@ -10,6 +10,8 @@ class SAOS < Oxidized::Model
|
|
10
10
|
end
|
11
11
|
|
12
12
|
cmd 'configuration show' do |cfg|
|
13
|
+
cfg.gsub! /^! Created: [^\n]*\n/, ''
|
14
|
+
cfg.gsub! /^! On terminal: [^\n]*\n/, ''
|
13
15
|
cfg
|
14
16
|
end
|
15
17
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Siklu < Oxidized::Model
|
2
|
+
|
3
|
+
# Siklu EtherHaul #
|
4
|
+
|
5
|
+
prompt /^[\w-]+>$/
|
6
|
+
|
7
|
+
cmd 'copy startup-configuration display' do |cfg|
|
8
|
+
cfg.each_line.to_a[2..2].join
|
9
|
+
end
|
10
|
+
|
11
|
+
cmd 'copy running-configuration display' do |cfg|
|
12
|
+
cfg.each_line.to_a[3..-2].join
|
13
|
+
end
|
14
|
+
|
15
|
+
cfg :ssh do
|
16
|
+
pre_logout 'exit'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/lib/oxidized/model/timos.rb
CHANGED
@@ -18,6 +18,8 @@ class TiMOS < Oxidized::Model
|
|
18
18
|
# Show the boot options file.
|
19
19
|
#
|
20
20
|
cmd 'show bof' do |cfg|
|
21
|
+
cfg.gsub! /# Finished .*/, ''
|
22
|
+
cfg.gsub! /# Generated .*/, ''
|
21
23
|
comment cfg
|
22
24
|
end
|
23
25
|
|
@@ -29,6 +31,8 @@ class TiMOS < Oxidized::Model
|
|
29
31
|
# Strip uptime.
|
30
32
|
#
|
31
33
|
cfg.sub! /^System Up Time.*\n/, ''
|
34
|
+
cfg.gsub! /# Finished .*/, ''
|
35
|
+
cfg.gsub! /# Generated .*/, ''
|
32
36
|
comment cfg
|
33
37
|
end
|
34
38
|
|
@@ -36,6 +40,8 @@ class TiMOS < Oxidized::Model
|
|
36
40
|
# Show the card state.
|
37
41
|
#
|
38
42
|
cmd 'show card state' do |cfg|
|
43
|
+
cfg.gsub! /# Finished .*/, ''
|
44
|
+
cfg.gsub! /# Generated .*/, ''
|
39
45
|
comment cfg
|
40
46
|
end
|
41
47
|
|
@@ -48,6 +54,8 @@ class TiMOS < Oxidized::Model
|
|
48
54
|
#
|
49
55
|
cfg.gsub! /\r/, ''
|
50
56
|
cfg.gsub! /[\b][\b][\b]/, "\n"
|
57
|
+
cfg.gsub! /# Finished .*/, ''
|
58
|
+
cfg.gsub! /# Generated .*/, ''
|
51
59
|
comment cfg
|
52
60
|
end
|
53
61
|
|
@@ -55,6 +63,8 @@ class TiMOS < Oxidized::Model
|
|
55
63
|
# Show the running debug configuration.
|
56
64
|
#
|
57
65
|
cmd 'show debug' do |cfg|
|
66
|
+
cfg.gsub! /# Finished .*/, ''
|
67
|
+
cfg.gsub! /# Generated .*/, ''
|
58
68
|
comment cfg
|
59
69
|
end
|
60
70
|
|
@@ -66,6 +76,8 @@ class TiMOS < Oxidized::Model
|
|
66
76
|
# Strip carriage returns.
|
67
77
|
#
|
68
78
|
cfg.gsub! /\r/, ''
|
79
|
+
cfg.gsub! /# Finished .*/, ''
|
80
|
+
cfg.gsub! /# Generated .*/, ''
|
69
81
|
comment cfg
|
70
82
|
end
|
71
83
|
|
@@ -77,6 +89,8 @@ class TiMOS < Oxidized::Model
|
|
77
89
|
# Strip carriage returns.
|
78
90
|
#
|
79
91
|
cfg.gsub! /\r/, ''
|
92
|
+
cfg.gsub! /# Finished .*/, ''
|
93
|
+
cfg.gsub! /# Generated .*/, ''
|
80
94
|
comment cfg
|
81
95
|
end
|
82
96
|
|
@@ -88,6 +102,8 @@ class TiMOS < Oxidized::Model
|
|
88
102
|
# Strip carriage returns.
|
89
103
|
#
|
90
104
|
cfg.gsub! /\r/, ''
|
105
|
+
cfg.gsub! /# Finished .*/, ''
|
106
|
+
cfg.gsub! /# Generated .*/, ''
|
91
107
|
end
|
92
108
|
|
93
109
|
cfg :telnet do
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class TPLink < Oxidized::Model
|
2
|
+
|
3
|
+
# tp-link prompt
|
4
|
+
prompt /^\r?([\w.@()-]+[#>]\s?)$/
|
5
|
+
comment '! '
|
6
|
+
|
7
|
+
# handle paging
|
8
|
+
# workaround for sometimes missing whitespaces with "\s?"
|
9
|
+
expect /Press\s?any\s?key\s?to\s?continue\s?\(Q\s?to\s?quit\)/ do |data, re|
|
10
|
+
send ' '
|
11
|
+
data.sub re, ''
|
12
|
+
end
|
13
|
+
|
14
|
+
# send carriage return because \n with the command is not enough
|
15
|
+
# checks if line ends with prompt >,# or \r,\nm otherwise send \r
|
16
|
+
expect /[^>#\r\n]$/ do |data, re|
|
17
|
+
send "\r"
|
18
|
+
data.sub re, ''
|
19
|
+
end
|
20
|
+
|
21
|
+
cmd :all do |cfg|
|
22
|
+
# normalize linefeeds
|
23
|
+
cfg.gsub! /(\r|\r\n|\n\r)/,"\n"
|
24
|
+
# remove empty lines
|
25
|
+
cfg.each_line.reject { |line| line.match /^[\r\n\s\u0000#]+$/ }.join
|
26
|
+
end
|
27
|
+
|
28
|
+
cmd :secret do |cfg|
|
29
|
+
cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
|
30
|
+
cfg.gsub! /secret (\d+) (\S+).*/, '<secret hidden>'
|
31
|
+
cfg
|
32
|
+
end
|
33
|
+
|
34
|
+
cmd 'show system-info' do |cfg|
|
35
|
+
comment cfg.each_line.to_a[3..-3].join
|
36
|
+
end
|
37
|
+
|
38
|
+
cmd 'show running-config' do |cfg|
|
39
|
+
lines = cfg.each_line.to_a[1..-1]
|
40
|
+
# cut config after "end"
|
41
|
+
lines[0..lines.index("end\n")].join
|
42
|
+
end
|
43
|
+
|
44
|
+
cfg :telnet, :ssh do
|
45
|
+
username /^User ?[nN]ame:/
|
46
|
+
password /^\r?Password:/
|
47
|
+
end
|
48
|
+
|
49
|
+
cfg :telnet, :ssh do
|
50
|
+
if vars :enable
|
51
|
+
post_login do
|
52
|
+
send "enable\r"
|
53
|
+
cmd vars(:enable)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
pre_logout do
|
58
|
+
send "exit\r"
|
59
|
+
send "logout\r"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|