dapp 0.6.1 → 0.6.2
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 +4 -4
- data/bin/dapp +3 -3
- data/config/en/common.yml +19 -4
- data/config/en/net_status.yml +13 -4
- data/lib/dapp.rb +48 -16
- data/lib/dapp/application.rb +75 -40
- data/lib/dapp/application/path.rb +3 -2
- data/lib/dapp/application/stages.rb +59 -0
- data/lib/dapp/artifact.rb +22 -0
- data/lib/dapp/build/stage/after_install_artifact.rb +13 -0
- data/lib/dapp/build/stage/after_setup_artifact.rb +17 -0
- data/lib/dapp/build/stage/artifact_base.rb +80 -0
- data/lib/dapp/build/stage/artifact_default.rb +62 -0
- data/lib/dapp/build/stage/base.rb +47 -12
- data/lib/dapp/build/stage/before_install.rb +6 -5
- data/lib/dapp/build/stage/before_install_artifact.rb +13 -0
- data/lib/dapp/build/stage/before_setup.rb +7 -8
- data/lib/dapp/build/stage/before_setup_artifact.rb +13 -0
- data/lib/dapp/build/stage/build_artifact.rb +32 -0
- data/lib/dapp/build/stage/docker_instructions.rb +4 -22
- data/lib/dapp/build/stage/from.rb +7 -8
- data/lib/dapp/build/stage/ga_archive.rb +1 -1
- data/lib/dapp/build/stage/ga_archive_dependencies.rb +1 -1
- data/lib/dapp/build/stage/ga_artifact_patch.rb +21 -0
- data/lib/dapp/build/stage/ga_base.rb +6 -29
- data/lib/dapp/build/stage/ga_dependencies_base.rb +4 -13
- data/lib/dapp/build/stage/ga_latest_patch.rb +2 -2
- data/lib/dapp/build/stage/import_artifact.rb +69 -0
- data/lib/dapp/build/stage/install/ga_post_install_patch.rb +1 -1
- data/lib/dapp/build/stage/install/ga_post_install_patch_dependencies.rb +1 -1
- data/lib/dapp/build/stage/install/ga_pre_install_patch_dependencies.rb +1 -7
- data/lib/dapp/build/stage/install/install.rb +12 -7
- data/lib/dapp/build/stage/mod/logging.rb +10 -7
- data/lib/dapp/build/stage/setup/chef_cookbooks.rb +3 -4
- data/lib/dapp/build/stage/setup/ga_post_setup_patch.rb +1 -1
- data/lib/dapp/build/stage/setup/ga_pre_setup_patch.rb +2 -2
- data/lib/dapp/build/stage/setup/ga_pre_setup_patch_dependencies.rb +2 -8
- data/lib/dapp/build/stage/setup/setup.rb +12 -7
- data/lib/dapp/builder/base.rb +13 -1
- data/lib/dapp/builder/chef.rb +125 -79
- data/lib/dapp/builder/chef/cookbook_metadata.rb +1 -1
- data/lib/dapp/builder/shell.rb +2 -3
- data/lib/dapp/cli.rb +3 -3
- data/lib/dapp/cli/base.rb +0 -2
- data/lib/dapp/cli/bp.rb +0 -4
- data/lib/dapp/cli/build.rb +3 -7
- data/lib/dapp/cli/cleanup.rb +0 -2
- data/lib/dapp/cli/list.rb +0 -2
- data/lib/dapp/cli/mrproper.rb +22 -0
- data/lib/dapp/cli/push.rb +4 -3
- data/lib/dapp/cli/run.rb +0 -2
- data/lib/dapp/cli/spush.rb +0 -2
- data/lib/dapp/cli/stage_image.rb +24 -0
- data/lib/dapp/cli/stages.rb +7 -5
- data/lib/dapp/cli/stages/cleanup_local.rb +28 -0
- data/lib/dapp/cli/stages/cleanup_repo.rb +24 -0
- data/lib/dapp/cli/stages/{flush.rb → flush_local.rb} +4 -6
- data/lib/dapp/cli/stages/{cleanup.rb → flush_repo.rb} +4 -6
- data/lib/dapp/cli/stages/pull.rb +28 -0
- data/lib/dapp/cli/stages/push.rb +24 -0
- data/lib/dapp/config/application.rb +185 -44
- data/lib/dapp/config/artifact.rb +10 -50
- data/lib/dapp/config/directive/artifact.rb +77 -0
- data/lib/dapp/config/directive/build_dir.rb +9 -0
- data/lib/dapp/config/directive/chef.rb +95 -0
- data/lib/dapp/config/directive/docker/artifact.rb +26 -0
- data/lib/dapp/config/directive/docker/base.rb +91 -0
- data/lib/dapp/config/directive/git_artifact.rb +59 -0
- data/lib/dapp/config/directive/shell/artifact.rb +38 -0
- data/lib/dapp/config/directive/shell/base.rb +85 -0
- data/lib/dapp/config/directive/tmp_dir.rb +36 -0
- data/lib/dapp/config/main.rb +1 -7
- data/lib/dapp/core_ext/hash.rb +21 -0
- data/lib/dapp/docker_registry/base.rb +60 -5
- data/lib/dapp/docker_registry/mod/request.rb +2 -14
- data/lib/dapp/git_artifact.rb +32 -23
- data/lib/dapp/git_repo/base.rb +1 -1
- data/lib/dapp/image/argument.rb +3 -3
- data/lib/dapp/image/docker.rb +13 -16
- data/lib/dapp/image/scratch.rb +29 -0
- data/lib/dapp/image/stage.rb +33 -23
- data/lib/dapp/lock/base.rb +18 -11
- data/lib/dapp/lock/file.rb +18 -16
- data/lib/dapp/prctl.rb +1 -0
- data/lib/dapp/project.rb +22 -9
- data/lib/dapp/project/command/bp.rb +2 -5
- data/lib/dapp/project/command/build.rb +1 -2
- data/lib/dapp/project/command/cleanup.rb +9 -7
- data/lib/dapp/project/command/common.rb +37 -12
- data/lib/dapp/project/command/mrproper.rb +57 -0
- data/lib/dapp/project/command/push.rb +8 -2
- data/lib/dapp/project/command/run.rb +1 -1
- data/lib/dapp/project/command/stage_image.rb +15 -0
- data/lib/dapp/project/command/stages/cleanup_local.rb +100 -0
- data/lib/dapp/project/command/stages/cleanup_repo.rb +65 -0
- data/lib/dapp/project/command/stages/common.rb +48 -0
- data/lib/dapp/project/command/stages/flush_local.rb +24 -0
- data/lib/dapp/project/command/stages/flush_repo.rb +22 -0
- data/lib/dapp/project/command/stages/pull.rb +26 -0
- data/lib/dapp/project/command/stages/push.rb +22 -0
- data/lib/dapp/project/dappfile.rb +3 -1
- data/lib/dapp/project/deps/base.rb +52 -0
- data/lib/dapp/project/deps/gitartifact.rb +36 -0
- data/lib/dapp/project/lock.rb +20 -13
- data/lib/dapp/project/logging/base.rb +20 -3
- data/lib/dapp/project/logging/i18n.rb +25 -0
- data/lib/dapp/project/logging/paint.rb +47 -0
- data/lib/dapp/project/logging/process.rb +17 -10
- data/lib/dapp/project/shellout/base.rb +74 -0
- data/lib/dapp/project/shellout/streaming.rb +49 -0
- data/lib/dapp/project/shellout/system.rb +72 -0
- data/lib/dapp/project/ssh_agent.rb +8 -9
- data/lib/dapp/version.rb +1 -1
- metadata +48 -17
- data/lib/dapp/build/stage/artifact.rb +0 -40
- data/lib/dapp/build/stage/mod/artifact.rb +0 -79
- data/lib/dapp/config/chef.rb +0 -51
- data/lib/dapp/config/docker.rb +0 -82
- data/lib/dapp/config/git_artifact.rb +0 -51
- data/lib/dapp/config/shell.rb +0 -64
- data/lib/dapp/helper/i18n.rb +0 -20
- data/lib/dapp/helper/paint.rb +0 -27
- data/lib/dapp/helper/shellout.rb +0 -63
- data/lib/dapp/helper/streaming.rb +0 -47
- data/lib/dapp/project/command/stages_cleanup.rb +0 -72
- data/lib/dapp/project/command/stages_flush.rb +0 -20
- data/lib/dapp/project/paint.rb +0 -16
data/lib/dapp/config/artifact.rb
CHANGED
@@ -1,60 +1,20 @@
|
|
1
1
|
module Dapp
|
2
2
|
module Config
|
3
3
|
# Artifact
|
4
|
-
|
5
|
-
|
6
|
-
class Base
|
7
|
-
attr_accessor :_where_to_add, :_cwd, :_paths, :_owner, :_group
|
4
|
+
class Artifact < Application
|
5
|
+
attr_reader :_artifact_dependencies
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
options.each do |k, v|
|
14
|
-
respond_to?("_#{k}=") ? send(:"_#{k}=", v) : raise(Error::Config, code: code,
|
15
|
-
data: { type: object_name, attr: k })
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def _paths
|
20
|
-
Array(@_paths)
|
21
|
-
end
|
22
|
-
|
23
|
-
def _artifact_options
|
24
|
-
{
|
25
|
-
where_to_add: _where_to_add,
|
26
|
-
cwd: _cwd,
|
27
|
-
paths: _paths,
|
28
|
-
owner: _owner,
|
29
|
-
group: _group
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
def clone
|
34
|
-
Marshal.load(Marshal.dump(self))
|
35
|
-
end
|
36
|
-
|
37
|
-
protected
|
38
|
-
|
39
|
-
def code
|
40
|
-
raise
|
41
|
-
end
|
42
|
-
|
43
|
-
def object_name
|
44
|
-
self.class.to_s.split('::').last
|
45
|
-
end
|
7
|
+
def initialize(parent)
|
8
|
+
@_artifact_dependencies = []
|
9
|
+
super
|
46
10
|
end
|
47
11
|
|
48
|
-
|
49
|
-
|
50
|
-
attr_accessor :_config
|
51
|
-
|
52
|
-
protected
|
53
|
-
|
54
|
-
def code
|
55
|
-
:artifact_unexpected_attribute
|
56
|
-
end
|
12
|
+
def artifact_depends_on(*args)
|
13
|
+
@_artifact_dependencies.concat(args)
|
57
14
|
end
|
15
|
+
|
16
|
+
undef_method :app
|
17
|
+
undef_method :artifact
|
58
18
|
end
|
59
19
|
end
|
60
20
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Config
|
3
|
+
module Directive
|
4
|
+
# Artifact
|
5
|
+
module Artifact
|
6
|
+
# Base
|
7
|
+
class Base
|
8
|
+
attr_accessor :_where_to_add, :_cwd, :_paths, :_exclude_paths, :_owner, :_group
|
9
|
+
|
10
|
+
def initialize(where_to_add, **options)
|
11
|
+
@_cwd = ''
|
12
|
+
@_where_to_add = where_to_add
|
13
|
+
|
14
|
+
options.each do |k, v|
|
15
|
+
respond_to?("_#{k}=") ? send(:"_#{k}=", v) : raise(Error::Config, code: code,
|
16
|
+
data: { type: object_name, attr: k })
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def _paths
|
21
|
+
base_paths(@_paths)
|
22
|
+
end
|
23
|
+
|
24
|
+
def _exclude_paths
|
25
|
+
base_paths(@_exclude_paths)
|
26
|
+
end
|
27
|
+
|
28
|
+
def _artifact_options
|
29
|
+
{
|
30
|
+
where_to_add: _where_to_add,
|
31
|
+
cwd: _cwd,
|
32
|
+
paths: _paths,
|
33
|
+
exclude_paths: _exclude_paths,
|
34
|
+
owner: _owner,
|
35
|
+
group: _group
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def clone
|
42
|
+
Marshal.load(Marshal.dump(self))
|
43
|
+
end
|
44
|
+
|
45
|
+
def base_paths(paths)
|
46
|
+
Array(paths)
|
47
|
+
end
|
48
|
+
|
49
|
+
def code
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
|
53
|
+
def object_name
|
54
|
+
self.class.to_s.split('::').last
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Stage
|
59
|
+
class Stage < Base
|
60
|
+
attr_accessor :_config
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def clone
|
65
|
+
artifact_options = Marshal.load(Marshal.dump(_artifact_options))
|
66
|
+
where_to_add = artifact_options.delete(:where_to_add)
|
67
|
+
self.class.new(where_to_add, config: _config, **artifact_options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def code
|
71
|
+
:artifact_unexpected_attribute
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Config
|
3
|
+
module Directive
|
4
|
+
# Chef
|
5
|
+
class Chef
|
6
|
+
attr_reader :_modules
|
7
|
+
attr_reader :_recipes
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@_modules = []
|
11
|
+
@_recipes = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def module(*args)
|
15
|
+
@_modules.concat(args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset_modules
|
19
|
+
@_modules.clear
|
20
|
+
end
|
21
|
+
|
22
|
+
def skip_module(*args)
|
23
|
+
@_modules.reject! { |mod| args.include? mod }
|
24
|
+
end
|
25
|
+
|
26
|
+
def recipe(*args)
|
27
|
+
@_recipes.concat(args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove_recipe(*args)
|
31
|
+
@_recipes.reject! { |recipe| args.include? recipe }
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset_recipes
|
35
|
+
@_recipes.clear
|
36
|
+
end
|
37
|
+
|
38
|
+
def attributes
|
39
|
+
@attributes ||= Attributes.new
|
40
|
+
end
|
41
|
+
|
42
|
+
%i(before_install install before_setup setup build_artifact).each do |stage|
|
43
|
+
define_method("#{stage}_attributes") do
|
44
|
+
var = "@#{stage}_attributes"
|
45
|
+
instance_variable_get(var) || instance_variable_set(var, Attributes.new)
|
46
|
+
end
|
47
|
+
|
48
|
+
define_method("_#{stage}_attributes") do
|
49
|
+
attributes.in_depth_merge send("#{stage}_attributes")
|
50
|
+
end
|
51
|
+
|
52
|
+
define_method("reset_#{stage}_attributes") do
|
53
|
+
instance_variable_set("@#{stage}_attributes", nil)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def reset_attributes
|
58
|
+
@attributes = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def reset_all_attributes
|
62
|
+
reset_attributes
|
63
|
+
%i(before_install install before_setup setup build_artifact).each do |stage|
|
64
|
+
send("reset_#{stage}_attributes")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def reset_all
|
69
|
+
reset_modules
|
70
|
+
reset_recipes
|
71
|
+
reset_all_attributes
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def clone
|
77
|
+
Marshal.load(Marshal.dump(self))
|
78
|
+
end
|
79
|
+
|
80
|
+
def empty?
|
81
|
+
@_modules.empty? && @_recipes.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
# Attributes
|
85
|
+
class Attributes < Hash
|
86
|
+
def [](key)
|
87
|
+
super || begin
|
88
|
+
self[key] = self.class.new
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end # Attributes
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Config
|
3
|
+
module Directive
|
4
|
+
# Docker
|
5
|
+
module Docker
|
6
|
+
# Artifact
|
7
|
+
class Artifact
|
8
|
+
attr_reader :_from
|
9
|
+
attr_reader :_from_cache_version
|
10
|
+
|
11
|
+
def from(image, cache_version: nil)
|
12
|
+
raise(Error::Config, code: :docker_from_incorrect, data: { name: image }) unless image =~ /^[[^ ].]+:[[^ ].]+$/
|
13
|
+
@_from = image
|
14
|
+
@_from_cache_version = cache_version
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def clone
|
20
|
+
Marshal.load(Marshal.dump(self))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Config
|
3
|
+
module Directive
|
4
|
+
# Docker
|
5
|
+
module Docker
|
6
|
+
# Base
|
7
|
+
class Base
|
8
|
+
attr_reader :_from, :_volume, :_expose, :_env, :_label, :_cmd, :_onbuild, :_workdir, :_user, :_entrypoint
|
9
|
+
attr_reader :_from_cache_version
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@_volume = []
|
13
|
+
@_expose = []
|
14
|
+
@_env = {}
|
15
|
+
@_label = {}
|
16
|
+
@_cmd = []
|
17
|
+
@_onbuild = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def from(image, cache_version: nil)
|
21
|
+
raise(Error::Config, code: :docker_from_incorrect, data: { name: image }) unless image =~ /^[[^ ].]+:[[^ ].]+$/
|
22
|
+
@_from = image
|
23
|
+
@_from_cache_version = cache_version
|
24
|
+
end
|
25
|
+
|
26
|
+
def volume(*args)
|
27
|
+
@_volume.concat(args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def expose(*args)
|
31
|
+
@_expose.concat(args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def env(**options)
|
35
|
+
@_env.merge!(options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def label(**options)
|
39
|
+
@_label.merge!(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def cmd(*args)
|
43
|
+
@_cmd.concat(args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def onbuild(*args)
|
47
|
+
@_onbuild.concat(args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def workdir(val)
|
51
|
+
@_workdir = val
|
52
|
+
end
|
53
|
+
|
54
|
+
def user(val)
|
55
|
+
@_user = val
|
56
|
+
end
|
57
|
+
|
58
|
+
def entrypoint(*cmd_with_args)
|
59
|
+
@_entrypoint = cmd_with_args.flatten
|
60
|
+
end
|
61
|
+
|
62
|
+
def _change_options
|
63
|
+
{
|
64
|
+
volume: _volume,
|
65
|
+
expose: _expose,
|
66
|
+
env: _env,
|
67
|
+
label: _label,
|
68
|
+
cmd: _cmd,
|
69
|
+
onbuild: _onbuild,
|
70
|
+
workdir: _workdir,
|
71
|
+
user: _user,
|
72
|
+
entrypoint: _entrypoint
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def clone
|
79
|
+
Marshal.load(Marshal.dump(self))
|
80
|
+
end
|
81
|
+
|
82
|
+
def clone_to_artifact
|
83
|
+
Artifact.new.tap do |docker|
|
84
|
+
docker.instance_variable_set('@_from', @_from)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Config
|
3
|
+
module Directive
|
4
|
+
# GitArtifact
|
5
|
+
class GitArtifact
|
6
|
+
attr_reader :_local
|
7
|
+
attr_reader :_remote
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@_local = []
|
11
|
+
@_remote = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def local(*args)
|
15
|
+
@_local.tap { |local| local << Local.new(*args) unless args.empty? }
|
16
|
+
end
|
17
|
+
|
18
|
+
def remote(*args)
|
19
|
+
@_remote.tap { |remote| remote << Remote.new(*args) unless args.empty? }
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def clone
|
25
|
+
Marshal.load(Marshal.dump(self))
|
26
|
+
end
|
27
|
+
|
28
|
+
def empty?
|
29
|
+
_local.empty? && _remote.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Local
|
33
|
+
class Local < Artifact::Base
|
34
|
+
protected
|
35
|
+
|
36
|
+
def code
|
37
|
+
:git_artifact_unexpected_attribute
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Remote
|
42
|
+
class Remote < Local
|
43
|
+
attr_accessor :_url, :_name, :_branch
|
44
|
+
|
45
|
+
def initialize(url, where_to_add, **options)
|
46
|
+
@_url = url
|
47
|
+
@_name = url.gsub(%r{.*?([^\/ ]+)\.git}, '\\1')
|
48
|
+
@_branch = options.delete(:branch)
|
49
|
+
super(where_to_add, **options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def _artifact_options
|
53
|
+
super.merge(name: _name, branch: _branch)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Config
|
3
|
+
module Directive
|
4
|
+
module Shell
|
5
|
+
# Artifact
|
6
|
+
class Artifact < Base
|
7
|
+
attr_reader :_build_artifact
|
8
|
+
attr_reader :_build_artifact_cache_version
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
@_build_artifact = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_artifact(*args, cache_version: nil)
|
16
|
+
@_build_artifact.concat(args)
|
17
|
+
@_build_artifact_cache_version = cache_version
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset_build_artifact
|
21
|
+
@_build_artifact = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset_all
|
25
|
+
super
|
26
|
+
reset_build_artifact
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def empty?
|
32
|
+
super && @_build_artifact.empty?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|