spawngebob 0.1.0 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -0
- data/bin/spawn +1 -1
- data/lib/spawngebob/cli.rb +35 -0
- data/lib/spawngebob/compilers/nginx.rb +10 -13
- data/lib/spawngebob/compilers.rb +1 -1
- data/lib/spawngebob/constants.rb +7 -7
- data/lib/spawngebob/runner.rb +47 -52
- data/lib/spawngebob/utils.rb +5 -0
- data/lib/spawngebob/version.rb +1 -1
- data/lib/spawngebob.rb +6 -8
- data/script/nginx +133 -0
- data/spawngebob.gemspec +1 -0
- metadata +18 -5
- data/lib/spawngebob/spawner.rb +0 -71
data/CHANGELOG
ADDED
data/bin/spawn
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Spawngebob
|
4
|
+
class CLI < Thor
|
5
|
+
desc "start", "start nginx"
|
6
|
+
def start
|
7
|
+
Runner.boot(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "stop", "stop nginx"
|
11
|
+
def stop
|
12
|
+
Runner.boot(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "restart", "restart nginx"
|
16
|
+
def restart
|
17
|
+
Runner.boot(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "reload", "reload nginx"
|
21
|
+
def reload
|
22
|
+
Runner.boot(options)
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "check", "check status of web server"
|
26
|
+
def check
|
27
|
+
Runner.boot(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "configure", "generate conf files"
|
31
|
+
def configure
|
32
|
+
Runner.boot(options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -9,14 +9,14 @@ module Spawngebob
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def prepare
|
12
|
-
if !File.exist?(@config_file_path)
|
13
|
-
raise "apps.yml not found in #{NGINX_CONF_PATH}"
|
14
|
-
end
|
15
|
-
|
16
12
|
@config = ERB.new(File.read(@config_file_path)).result(binding)
|
17
13
|
@config = YAML.load(@config)
|
18
14
|
|
19
|
-
|
15
|
+
if !@config.is_a? Hash
|
16
|
+
Utils.error "Garbage #{CONFIG_FILE}! Fix it!"
|
17
|
+
else
|
18
|
+
compile!
|
19
|
+
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def compile!
|
@@ -29,12 +29,11 @@ module Spawngebob
|
|
29
29
|
if @config['nginx'].include? 'port'
|
30
30
|
NGINX_DEFAULTS.update(@config['nginx'])
|
31
31
|
end
|
32
|
-
puts NGINX_DEFAULTS.inspect
|
33
32
|
|
34
33
|
if @config['nginx']['ssl']
|
35
|
-
location_template = NGINX_SSL_LOCATION_TEMPLATE
|
34
|
+
location_template = NGINX_SSL_LOCATION_TEMPLATE.chomp!
|
36
35
|
else
|
37
|
-
location_template = NGINX_HTTP_LOCATION_TEMPLATE
|
36
|
+
location_template = NGINX_HTTP_LOCATION_TEMPLATE.chomp!
|
38
37
|
end
|
39
38
|
|
40
39
|
# apps
|
@@ -71,12 +70,10 @@ module Spawngebob
|
|
71
70
|
|
72
71
|
@container.concat(s)
|
73
72
|
end
|
73
|
+
end
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
FileUtils.mkdir_p(confd_path) if !File.exist? confd_path
|
78
|
-
|
79
|
-
File.open(File.join(confd_path, 'caresharing.conf'), 'w') do |f|
|
75
|
+
File.open(File.join(NGINX_CONFD_PATH, 'caresharing.conf'), 'w') do |f|
|
76
|
+
Utils.say_with_time "Generating new config file..." do
|
80
77
|
f.write(@container)
|
81
78
|
end
|
82
79
|
end
|
data/lib/spawngebob/compilers.rb
CHANGED
data/lib/spawngebob/constants.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
module Spawngebob
|
2
2
|
module Constants
|
3
|
+
BASE_CONFIG_PATH = File.join(ENV['HOME'], '.spawngebob')
|
4
|
+
NGINX_PATH = File.join(BASE_CONFIG_PATH, 'nginx')
|
5
|
+
NGINX_CONF_PATH = File.join(NGINX_PATH, 'conf')
|
6
|
+
NGINX_CONFD_PATH = File.join(NGINX_PATH, 'conf.d')
|
7
|
+
NGINX_CONF = 'nginx.conf'
|
8
|
+
NGINX_PID = 'nginx.pid'
|
3
9
|
NGINX_DIRS = ['tmp', 'run', 'logs', 'conf.d', 'conf']
|
4
10
|
CONFIG_FILE = 'apps.yml'
|
11
|
+
SCRIPT_DIR = File.expand_path(File.join(File.dirname(__FILE__), '../../script/nginx'))
|
5
12
|
|
6
13
|
NGINX_DEFAULTS = {
|
7
14
|
'listen' => '127.0.0.1',
|
8
15
|
'port' => '8088'
|
9
16
|
}
|
10
17
|
|
11
|
-
COLORS = {
|
12
|
-
:green => "\033[1;32m",
|
13
|
-
:red => "\033[1;31m",
|
14
|
-
:yellow =>"\033[1;33m",
|
15
|
-
:blank => "\033[0m"
|
16
|
-
}
|
17
|
-
|
18
18
|
NGINX_UPSTREAM_TEMPLATE = <<NUT
|
19
19
|
# %app%
|
20
20
|
upstream %app%_proxy {
|
data/lib/spawngebob/runner.rb
CHANGED
@@ -4,82 +4,77 @@ module Spawngebob
|
|
4
4
|
class Runner
|
5
5
|
include Constants
|
6
6
|
|
7
|
-
def self.boot(
|
8
|
-
Spawngebob::Constants.const_set('BASE_CONFIG_PATH', File.join(ENV['HOME'], '.spawngebob'))
|
9
|
-
Spawngebob::Constants.const_set('NGINX_CONFIG_PATH', File.join(BASE_CONFIG_PATH, 'nginx', '/'))
|
10
|
-
Spawngebob::Constants.const_set('NGINX_CONF', File.join(NGINX_CONFIG_PATH, 'conf', 'nginx.conf'))
|
11
|
-
Spawngebob::Constants.const_set('NGINX_PID', File.join(NGINX_CONFIG_PATH, 'run', 'nginx.pid'))
|
7
|
+
def self.boot(options)
|
12
8
|
Spawngebob::Constants.const_set('NGINX_BIN', `which nginx 2>/dev/null`.strip)
|
13
9
|
Spawngebob::Constants.const_set('KILL_BIN', `which kill 2>/dev/null`.strip)
|
14
10
|
|
15
|
-
self.new(
|
11
|
+
self.new(options) if has_requirements?
|
16
12
|
end
|
17
13
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
14
|
+
def self.has_requirements?
|
15
|
+
# create necessary directories if not exist
|
16
|
+
NGINX_DIRS.each do |d|
|
17
|
+
full_path = File.join(NGINX_PATH, d)
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
opts.on('-v', '--verbose', 'Verbose') do
|
27
|
-
@options[:verbose] = true
|
19
|
+
if !File.exists? full_path
|
20
|
+
Utils.say_with_time "Directory #{full_path} does not exist, creating..." do
|
21
|
+
FileUtils.mkdir_p(full_path)
|
22
|
+
end
|
28
23
|
end
|
24
|
+
end
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
# check if nginx is installed
|
27
|
+
if !Constants.const_defined?("NGINX_BIN")
|
28
|
+
Utils.error "Nginx is not installed!"
|
29
|
+
end
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
# check if nginx.conf exist
|
32
|
+
nginx_conf = File.join(NGINX_CONF_PATH, NGINX_CONF)
|
33
|
+
if !File.exists?(nginx_conf)
|
34
|
+
Utils.error "#{NGINX_CONF} not found in #{NGINX_CONF_PATH}"
|
39
35
|
end
|
40
36
|
|
41
|
-
|
37
|
+
if File.zero?(nginx_conf)
|
38
|
+
Utils.error "#{NGINX_CONF} is empty."
|
39
|
+
end
|
42
40
|
|
43
|
-
if
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
full_path = File.join(NGINX_CONFIG_PATH, d)
|
41
|
+
# check if apps.yml exists
|
42
|
+
apps_config = File.join(BASE_CONFIG_PATH, CONFIG_FILE)
|
43
|
+
if !File.exists?(apps_config)
|
44
|
+
Utils.error "#{CONFIG_FILE} not found in #{BASE_CONFIG_PATH}"
|
45
|
+
end
|
49
46
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
47
|
+
if File.zero?(apps_config)
|
48
|
+
Utils.error "#{CONFIG_FILE} is empty."
|
49
|
+
end
|
54
50
|
|
55
|
-
|
56
|
-
|
57
|
-
self.run(args)
|
58
|
-
else
|
59
|
-
raise "Missing nginx.conf in #{NGINX_CONF}!"
|
60
|
-
end
|
61
|
-
else
|
62
|
-
raise "Nginx is not installed!"
|
63
|
-
end
|
51
|
+
true
|
52
|
+
end
|
64
53
|
|
65
|
-
|
54
|
+
def initialize(options)
|
55
|
+
@options = options
|
56
|
+
@args = ARGV.dup
|
57
|
+
@command = ARGV.shift
|
58
|
+
|
59
|
+
self.run(options)
|
66
60
|
end
|
67
61
|
|
68
|
-
def run(
|
69
|
-
case args.shift
|
62
|
+
def run(options)
|
63
|
+
case @args.shift
|
70
64
|
when 'start'
|
71
|
-
|
65
|
+
system "#{SCRIPT_DIR} start"
|
72
66
|
when 'stop'
|
73
|
-
|
67
|
+
system "#{SCRIPT_DIR} stop"
|
74
68
|
when 'restart'
|
75
|
-
|
76
|
-
Spawner.start(@options)
|
69
|
+
system "#{SCRIPT_DIR} restart"
|
77
70
|
when 'check'
|
78
|
-
|
71
|
+
system "#{SCRIPT_DIR} status"
|
72
|
+
when 'reload'
|
73
|
+
system "#{SCRIPT_DIR} reload"
|
79
74
|
when 'configure'
|
80
75
|
Compilers::Nginx.new.prepare
|
81
76
|
else
|
82
|
-
puts "
|
77
|
+
puts "Unknown command! Available commands: {start|stop|restart|check|reload|configure}"
|
83
78
|
end
|
84
79
|
end
|
85
80
|
end
|
data/lib/spawngebob/utils.rb
CHANGED
data/lib/spawngebob/version.rb
CHANGED
data/lib/spawngebob.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'erb'
|
3
3
|
require 'fileutils'
|
4
|
-
require
|
5
|
-
|
6
|
-
SPAWNGEBOB_LIB_ROOT = File.join(File.dirname(__FILE__), 'spawngebob')
|
4
|
+
require 'spawngebob/version'
|
7
5
|
|
8
6
|
module Spawngebob
|
9
7
|
|
10
|
-
autoload :
|
11
|
-
autoload :Compilers,
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :Utils,
|
8
|
+
autoload :CLI, 'spawngebob/cli'
|
9
|
+
autoload :Compilers, 'spawngebob/compilers'
|
10
|
+
autoload :Constants, 'spawngebob/constants'
|
11
|
+
autoload :Runner, 'spawngebob/runner'
|
12
|
+
autoload :Utils, 'spawngebob/utils'
|
15
13
|
end
|
data/script/nginx
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
#!/usr/bin/env sh
|
2
|
+
nginx=`which nginx`
|
3
|
+
nginx_path=$HOME/.spawngebob/nginx/
|
4
|
+
pid_file="${nginx_path}run/nginx.pid"
|
5
|
+
prog=$(basename $nginx)
|
6
|
+
|
7
|
+
# colors
|
8
|
+
green="\033[0;32m"
|
9
|
+
yellow="\033[0;33m"
|
10
|
+
red="\033[0;31m"
|
11
|
+
clear="\033[0;0m"
|
12
|
+
nginx_conf_file="$HOME/.spawngebob/nginx/conf/nginx.conf"
|
13
|
+
|
14
|
+
lockfile=$HOME/.spawngebob/nginx/tmp/nginx.lock
|
15
|
+
|
16
|
+
notice() {
|
17
|
+
echo ""
|
18
|
+
echo "*************** NOTE **********************************"
|
19
|
+
echo " if a permission denied ALERT pops up, ignore it "
|
20
|
+
echo " info: http://wiki.nginx.org/CoreModule#error_log "
|
21
|
+
echo "*******************************************************"
|
22
|
+
echo ""
|
23
|
+
}
|
24
|
+
|
25
|
+
start() {
|
26
|
+
[ -x $nginx ] || exit 5
|
27
|
+
[ -f $nginx_conf_file ] || exit 6
|
28
|
+
|
29
|
+
echo $yellow"Starting $prog:"$clear
|
30
|
+
|
31
|
+
|
32
|
+
notice
|
33
|
+
|
34
|
+
if [ -f $lockfile ] ; then
|
35
|
+
echo $red" [fail]"$clear "lockfile $lockfile exists. nginx is running with master pid $yellow`cat $pid_file`$clear";
|
36
|
+
exit 8
|
37
|
+
fi
|
38
|
+
|
39
|
+
$nginx -c $nginx_conf_file -p $nginx_path
|
40
|
+
|
41
|
+
retval=$?
|
42
|
+
|
43
|
+
if [ $retval -eq 0 ] ; then
|
44
|
+
touch $lockfile
|
45
|
+
chmod 600 $lockfile
|
46
|
+
echo $green" [ok]"$clear" $prog started with master pid `cat $pid_file`"
|
47
|
+
else
|
48
|
+
echo $red " [fail]" $clear"Something went wrong." && exit 8
|
49
|
+
fi
|
50
|
+
|
51
|
+
return $retval
|
52
|
+
}
|
53
|
+
|
54
|
+
stop() {
|
55
|
+
echo $yellow"Stopping $prog..."$clear
|
56
|
+
|
57
|
+
echo "checking $pid_file..."
|
58
|
+
|
59
|
+
if [ -s $pid_file ] ; then
|
60
|
+
pid=`cat $pid_file`
|
61
|
+
echo "trying to kill pid $pid"
|
62
|
+
kill $pid && echo $green" [ok]"$clear "pid $yellow$pid$clear killed"
|
63
|
+
else
|
64
|
+
echo $red" [fail] "$clear"pidfile $pid_file not found" && exit 8
|
65
|
+
fi
|
66
|
+
|
67
|
+
retval=$?
|
68
|
+
|
69
|
+
if [ $retval -eq 0 ] ; then
|
70
|
+
notice
|
71
|
+
|
72
|
+
if [ -f $lockfile ] ; then
|
73
|
+
echo "removing $lockfile..."
|
74
|
+
rm -f $lockfile && echo $green" [ok]"$clear "lockfile deleted"
|
75
|
+
else
|
76
|
+
echo $red " [fail]" $clear"lockfile $lockfile not found" && exit 8
|
77
|
+
fi
|
78
|
+
else
|
79
|
+
echo $red " [fail]" $clear"Something went wrong." && exit 8
|
80
|
+
fi
|
81
|
+
|
82
|
+
return $retval
|
83
|
+
}
|
84
|
+
|
85
|
+
restart() {
|
86
|
+
configtest || return $?
|
87
|
+
stop
|
88
|
+
start
|
89
|
+
}
|
90
|
+
|
91
|
+
reload() {
|
92
|
+
configtest || return $?
|
93
|
+
echo $yellow"Reloading $prog:"$clear
|
94
|
+
|
95
|
+
notice
|
96
|
+
|
97
|
+
kill -HUP `cat $pid_file` && echo $green" [ok]"$clear " reloaded!"
|
98
|
+
retval=$?
|
99
|
+
}
|
100
|
+
|
101
|
+
configtest() {
|
102
|
+
echo $yellow"Testing configuration for $prog..."$clear
|
103
|
+
$nginx -t -c $nginx_conf_file -p $nginx_path
|
104
|
+
}
|
105
|
+
|
106
|
+
status() {
|
107
|
+
if [ -f $pid_file ] ; then
|
108
|
+
echo $green" [ok]"$clear "nginx is running smoothly with pid `cat $pid_file`"
|
109
|
+
else
|
110
|
+
echo $red" [fail] "$clear"pidfile $pid_file not found" && exit 8
|
111
|
+
fi
|
112
|
+
}
|
113
|
+
|
114
|
+
case "$1" in
|
115
|
+
start)
|
116
|
+
$1
|
117
|
+
;;
|
118
|
+
stop)
|
119
|
+
$1
|
120
|
+
;;
|
121
|
+
restart|configtest)
|
122
|
+
$1
|
123
|
+
;;
|
124
|
+
reload)
|
125
|
+
$1
|
126
|
+
;;
|
127
|
+
status)
|
128
|
+
$1
|
129
|
+
;;
|
130
|
+
*)
|
131
|
+
echo $"Usage: $0 {start|stop|status|restart|reload|configtest}"
|
132
|
+
exit 2
|
133
|
+
esac
|
data/spawngebob.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spawngebob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,19 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-05-10 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &70360117758740 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70360117758740
|
14
25
|
description: ''
|
15
26
|
email:
|
16
27
|
- poymode@gmail.com
|
@@ -20,19 +31,21 @@ extensions: []
|
|
20
31
|
extra_rdoc_files: []
|
21
32
|
files:
|
22
33
|
- .gitignore
|
34
|
+
- CHANGELOG
|
23
35
|
- Gemfile
|
24
36
|
- Rakefile
|
25
37
|
- bin/spawn
|
26
38
|
- lib/spawngebob.rb
|
39
|
+
- lib/spawngebob/cli.rb
|
27
40
|
- lib/spawngebob/compilers.rb
|
28
41
|
- lib/spawngebob/compilers/nginx.rb
|
29
42
|
- lib/spawngebob/constants.rb
|
30
43
|
- lib/spawngebob/runner.rb
|
31
|
-
- lib/spawngebob/spawner.rb
|
32
44
|
- lib/spawngebob/utils.rb
|
33
45
|
- lib/spawngebob/version.rb
|
34
46
|
- lib/templates/apps.yml.sample
|
35
47
|
- lib/templates/nginx.conf.sample
|
48
|
+
- script/nginx
|
36
49
|
- spawngebob.gemspec
|
37
50
|
homepage: ''
|
38
51
|
licenses: []
|
@@ -54,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
67
|
version: '0'
|
55
68
|
requirements: []
|
56
69
|
rubyforge_project: spawngebob
|
57
|
-
rubygems_version: 1.8.
|
70
|
+
rubygems_version: 1.8.17
|
58
71
|
signing_key:
|
59
72
|
specification_version: 3
|
60
73
|
summary: user based webserver non-root-runner and configurator
|
data/lib/spawngebob/spawner.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
module Spawngebob
|
2
|
-
class Spawner
|
3
|
-
include Constants
|
4
|
-
|
5
|
-
def self.start(opts, flag = false)
|
6
|
-
if get_pid && get_worker_pids
|
7
|
-
if flag
|
8
|
-
Utils.say "nginx #{COLORS[:green]}STARTED!#{COLORS[:blank]}"
|
9
|
-
else
|
10
|
-
Utils.say "nginx already #{COLORS[:yellow]}EXISTS!#{COLORS[:blank]}"
|
11
|
-
check
|
12
|
-
end
|
13
|
-
exit
|
14
|
-
else
|
15
|
-
Utils.say_with_time "starting nginx..." do
|
16
|
-
Dir.chdir(NGINX_CONFIG_PATH) do
|
17
|
-
if opts[:verbose]
|
18
|
-
`#{NGINX_BIN} -c #{NGINX_CONF} -p #{NGINX_CONFIG_PATH}`
|
19
|
-
else
|
20
|
-
`#{NGINX_BIN} -c #{NGINX_CONF} -p #{NGINX_CONFIG_PATH} 2>&1`
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
check
|
26
|
-
end
|
27
|
-
|
28
|
-
start(opts, true)
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.has_pid?
|
32
|
-
File.exist?(NGINX_PID) && !File.zero?(NGINX_PID)
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.get_pid
|
36
|
-
if has_pid?
|
37
|
-
File.read(NGINX_PID).chomp!
|
38
|
-
else
|
39
|
-
Utils.say "#{COLORS[:red]}pid does not exist!#{COLORS[:blank]}"
|
40
|
-
false
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.stop
|
45
|
-
pid = get_pid
|
46
|
-
|
47
|
-
if pid
|
48
|
-
Utils.say_with_time "killing #{COLORS[:yellow]}#{pid}#{COLORS[:blank]}..." do
|
49
|
-
`#{KILL_BIN} #{pid}`
|
50
|
-
end
|
51
|
-
|
52
|
-
if FileUtils.rm_rf(NGINX_PID)
|
53
|
-
Utils.say "#{COLORS[:green]}pid removed!#{COLORS[:blank]}"
|
54
|
-
end
|
55
|
-
else
|
56
|
-
Utils.say "#{COLORS[:red]}nginx not running!#{COLORS[:blank]}"
|
57
|
-
exit
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.get_worker_pids
|
62
|
-
worker_pids = `ps ax | grep 'nginx' | grep -v grep | awk '{print $1}'`
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.check
|
66
|
-
if get_pid && get_worker_pids
|
67
|
-
Utils.say "nginx is running: #{COLORS[:green]}#{get_pid}#{COLORS[:blank]}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|