esr-rim 1.3.8 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YTAzMzg0MDJmNmNiNDIzZDA5MWJiNDUwNTkyNWJlZmQ3M2Q2MzliMg==
5
- data.tar.gz: !binary |-
6
- YjgwYzMzMWM3NGNiNWM5NWQxMGQ5MDYzZDg2NjRkMTI3N2VhMDBiYQ==
2
+ SHA256:
3
+ metadata.gz: 92a6cf9a777ebf7199d6642919737640ed4194dc18b191973cc51612d196f4b5
4
+ data.tar.gz: 1254ea13f802865c004cac16759b71c509b42026c735da1838e98ecce0f75816
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZjVhNzBkZWIyNWMyMjM3ZDJiZTI2MjY1NmVlODVhYjYwYmFhNTk5ZjVjMjJi
10
- NGJlMDViZGFmZDA0M2I1ZGNiM2VhN2NmMTY0ZmE0ODRmOTEyNzFiNjA1M2Y1
11
- ZGI2NjE5ZDQ5NDE5Y2M5NjE1ODM0N2UzZTNhZTAyNmM4MjcyMTQ=
12
- data.tar.gz: !binary |-
13
- NjRkMjg1Nzg1MDgzMjQxOGM2NTM1NzQ0ZDg1ZGE0NTk5NDM4MzFiMTIyZTg1
14
- ZjViMDg5YmE1NmNiMzRhNDcwMWRlNGE3Y2JlNTU3Y2M2YjhlMTAzNDUzZGM1
15
- NmNkY2ZhNTJmYjJkMjIzNDQ3ODk3NTE1MTkwZjdjYTdmZGYzYmI=
6
+ metadata.gz: 0aa2478abeecc42a19eeccbfa30b7769811a62c17593c9d2384b00d73e4fb9a640b68ab65019f97ee967ffaba0a9d56222ec0c54af4289d920960aa4fff2f4b6
7
+ data.tar.gz: 55dec8e4158dfe395db31d92174dbd42eff729f6a36292903e0df90abbc6a3311ea98545126470af72a309d2dc540583aba7e7b4d37a89a2ebb20586856f798e
data/CHANGELOG CHANGED
@@ -118,3 +118,28 @@
118
118
  # 1.3.8
119
119
 
120
120
  * Normalize also path set in HOME before using (fixes problems with backslash used in Windows).
121
+
122
+ # 1.3.9
123
+
124
+ * Changed handling of parallel tasks due to robustness problems
125
+
126
+ # 1.4.0
127
+
128
+ * fixed Issue #20: Add revision timestamp to .riminfo
129
+
130
+ # 1.4.1
131
+
132
+ * Allow changing sub directory path to empty string
133
+ * Fix tar usage for Windows
134
+
135
+ # 1.4.2
136
+
137
+ * Fixed temporary-folder-generation on Windows, which could e.g. break the dirty check
138
+
139
+ # 1.4.3
140
+
141
+ * Fixed ignore-filter which could break if temporary files are created and deleted in parallel processes
142
+
143
+ # 1.4.4
144
+
145
+ * Fixed exception which results in ugly log output for Ruby >= 2.5 (Thread.report_on_exception)
data/Rakefile CHANGED
@@ -1,56 +1,56 @@
1
- $:.unshift(File.dirname(__FILE__)+"/lib")
2
-
3
- require 'rubygems/package_task'
4
- require 'rdoc/task'
5
- require 'rim/version'
6
-
7
- DocFiles = [
8
- "README.md", "CHANGELOG"
9
- ]
10
-
11
- RTextGemSpec = Gem::Specification.new do |s|
12
- s.name = "esr-rim"
13
- s.version = RIM::Version::Version
14
- s.date = Time.now.strftime("%Y-%m-%d")
15
- s.summary = "RIM - multi git tool"
16
- s.description = "RIM lets you work with multiple git repositories from within one single git repository."
17
- s.authors = "ESR Labs AG"
18
- s.homepage = "http://github.com/esrlabs/esr-rim"
19
- s.add_dependency('subcommand', '>= 1.0.6')
20
- gemfiles = Rake::FileList.new
21
- gemfiles.include("{lib,test}/**/*")
22
- gemfiles.include(DocFiles)
23
- gemfiles.include("Rakefile")
24
- s.files = gemfiles
25
- s.rdoc_options = ["--main", "README.md", "-x", "test"]
26
- s.extra_rdoc_files = DocFiles
27
- s.bindir = "bin"
28
- s.executables = ["rim"]
29
- end
30
-
31
- RDoc::Task.new do |rd|
32
- rd.main = "README.md"
33
- rd.rdoc_files.include(DocFiles)
34
- rd.rdoc_files.include("lib/**/*.rb")
35
- rd.rdoc_dir = "doc"
36
- end
37
-
38
- RTextPackageTask = Gem::PackageTask.new(RTextGemSpec) do |p|
39
- p.need_zip = false
40
- end
41
-
42
- task :prepare_package_rdoc => :rdoc do
43
- RTextPackageTask.package_files.include("doc/**/*")
44
- end
45
-
46
- desc 'run unit tests'
47
- task :run_tests do
48
- sh "ruby test/unit_tests.rb"
49
- end
50
-
51
- task :release => [:prepare_package_rdoc, :package]
52
-
53
- task :clobber => [:clobber_rdoc, :clobber_package]
54
-
55
- task :default => :run_tests
56
-
1
+ $:.unshift(File.dirname(__FILE__)+"/lib")
2
+
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ require 'rim/version'
6
+
7
+ DocFiles = [
8
+ "README.md", "CHANGELOG"
9
+ ]
10
+
11
+ RTextGemSpec = Gem::Specification.new do |s|
12
+ s.name = "esr-rim"
13
+ s.version = RIM::Version::Version
14
+ s.date = Time.now.strftime("%Y-%m-%d")
15
+ s.summary = "RIM - multi git tool"
16
+ s.description = "RIM lets you work with multiple git repositories from within one single git repository."
17
+ s.authors = "ESR Labs AG"
18
+ s.homepage = "http://github.com/esrlabs/esr-rim"
19
+ s.add_dependency('subcommand', '>= 1.0.6')
20
+ gemfiles = Rake::FileList.new
21
+ gemfiles.include("{lib,test}/**/*")
22
+ gemfiles.include(DocFiles)
23
+ gemfiles.include("Rakefile")
24
+ s.files = gemfiles
25
+ s.rdoc_options = ["--main", "README.md", "-x", "test"]
26
+ s.extra_rdoc_files = DocFiles
27
+ s.bindir = "bin"
28
+ s.executables = ["rim"]
29
+ end
30
+
31
+ RDoc::Task.new do |rd|
32
+ rd.main = "README.md"
33
+ rd.rdoc_files.include(DocFiles)
34
+ rd.rdoc_files.include("lib/**/*.rb")
35
+ rd.rdoc_dir = "doc"
36
+ end
37
+
38
+ RTextPackageTask = Gem::PackageTask.new(RTextGemSpec) do |p|
39
+ p.need_zip = false
40
+ end
41
+
42
+ task :prepare_package_rdoc => :rdoc do
43
+ RTextPackageTask.package_files.include("doc/**/*")
44
+ end
45
+
46
+ desc 'run unit tests'
47
+ task :run_tests do
48
+ sh "ruby test/unit_tests.rb"
49
+ end
50
+
51
+ task :release => [:prepare_package_rdoc, :package]
52
+
53
+ task :clobber => [:clobber_rdoc, :clobber_package]
54
+
55
+ task :default => :run_tests
56
+
@@ -1,89 +1,89 @@
1
- require 'rim/command/command'
2
- require 'rim/manifest/helper'
3
- require 'rim/rim_exception'
4
- require 'rim/rim_info'
5
- require 'rim/sync_helper'
6
- require 'uri'
7
-
8
- module RIM
9
- module Command
10
-
11
- class Sync < Command
12
-
13
- include RIM::Manifest
14
-
15
- def initialize(opts)
16
- opts.banner = "Usage: rim sync [<options>] [<local_module_path>]"
17
- opts.description = "Synchronize specified rim modules with remote repository revisions."
18
- opts.separator ""
19
- opts.on("-m", "--manifest [MANIFEST]", String, "Read information from manifest.", \
20
- "If no manifest file is specified a 'manifest.rim' file will be used.") do |manifest|
21
- @manifest = manifest ? manifest : Helpers::default_manifest
22
- end
23
- opts.on("-c", "--create", "Synchronize module initially to <local_module_path>.", \
24
- "Specify the remote URL and the target revision with the options.") do
25
- @create = true
26
- end
27
- opts.on("-a", "--all", "Collects all modules from the specified paths.") do
28
- @all = true
29
- end
30
- opts.on("-e", "--exclude PATTERN_LIST", String, "Exclude all modules of a comma separated list of directories when using sync with -a option.") do |dirlist|
31
- @excludedirs = dirlist.split(",")
32
- end
33
- @module_options = {}
34
- opts.on("-u", "--remote-url URL", String, "Set the remote URL of the module.", \
35
- "A relative path will be applied to ssh://gerrit/") do |url|
36
- @module_options[:remote_url] = url
37
- end
38
- opts.on("-r", "--target-revision REVISION", String, "Set the target revision of the module.") do |target_revision|
39
- @module_options[:target_revision] = target_revision
40
- end
41
- opts.on("-i", "--ignore PATTERN_LIST", String, "Set the ignore patterns by specifying a comma separated list.") do |ignores|
42
- @module_options[:ignores] = ignores || ""
43
- end
44
- opts.on("-m", "--message MESSAGE", String, "Message header to provide to each commit.") do |message|
45
- @message = message
46
- end
47
- opts.on("-d", "--subdir SUBDIR", String, "Sync just a subdir from the remote module.") do |subdir|
48
- @module_options[:subdir] = subdir
49
- end
50
- opts.on("-s", "--split", "Create a separate commit for each module.") do
51
- @split = true
52
- end
53
- opts.on("-b", "--rebase", "Rebase after successful sync.") do
54
- @rebase = true
55
- end
56
- end
57
-
58
- def invoke()
59
- helper = SyncHelper.new(project_git_dir, @logger)
60
- if @manifest
61
- helper.modules_from_manifest(@manifest)
62
- elsif @create
63
- local_path = ARGV.shift || "."
64
- if helper.find_file_dir_in_workspace(local_path, RimInfo::InfoFileName)
65
- raise RimException.new("There's already a module file. Don't use the create option to sync the module.")
66
- elsif !@module_options[:remote_url] || !@module_options[:target_revision]
67
- raise RimException.new("Please specify remote URL and target revision for the new module.")
68
- else
69
- helper.add_module_info(helper.create_module_info(
70
- @module_options[:remote_url],
71
- local_path,
72
- @module_options[:target_revision],
73
- @module_options[:ignores],
74
- @module_options[:subdir],
75
- ))
76
- end
77
- else
78
- helper.modules_from_paths(@all ? helper.module_paths(ARGV, @excludedirs) : ARGV, @module_options)
79
- end
80
- helper.check_arguments
81
- helper.sync(@message, @rebase, @split)
82
- end
83
-
84
- end
85
-
86
- end
87
- end
88
-
89
-
1
+ require 'rim/command/command'
2
+ require 'rim/manifest/helper'
3
+ require 'rim/rim_exception'
4
+ require 'rim/rim_info'
5
+ require 'rim/sync_helper'
6
+ require 'uri'
7
+
8
+ module RIM
9
+ module Command
10
+
11
+ class Sync < Command
12
+
13
+ include RIM::Manifest
14
+
15
+ def initialize(opts)
16
+ opts.banner = "Usage: rim sync [<options>] [<local_module_path>]"
17
+ opts.description = "Synchronize specified rim modules with remote repository revisions."
18
+ opts.separator ""
19
+ opts.on("-m", "--manifest [MANIFEST]", String, "Read information from manifest.", \
20
+ "If no manifest file is specified a 'manifest.rim' file will be used.") do |manifest|
21
+ @manifest = manifest ? manifest : Helpers::default_manifest
22
+ end
23
+ opts.on("-c", "--create", "Synchronize module initially to <local_module_path>.", \
24
+ "Specify the remote URL and the target revision with the options.") do
25
+ @create = true
26
+ end
27
+ opts.on("-a", "--all", "Collects all modules from the specified paths.") do
28
+ @all = true
29
+ end
30
+ opts.on("-e", "--exclude PATTERN_LIST", String, "Exclude all modules of a comma separated list of directories when using sync with -a option.") do |dirlist|
31
+ @excludedirs = dirlist.split(",")
32
+ end
33
+ @module_options = {}
34
+ opts.on("-u", "--remote-url URL", String, "Set the remote URL of the module.", \
35
+ "A relative path will be applied to ssh://gerrit/") do |url|
36
+ @module_options[:remote_url] = url
37
+ end
38
+ opts.on("-r", "--target-revision REVISION", String, "Set the target revision of the module.") do |target_revision|
39
+ @module_options[:target_revision] = target_revision
40
+ end
41
+ opts.on("-i", "--ignore PATTERN_LIST", String, "Set the ignore patterns by specifying a comma separated list.") do |ignores|
42
+ @module_options[:ignores] = ignores || ""
43
+ end
44
+ opts.on("-m", "--message MESSAGE", String, "Message header to provide to each commit.") do |message|
45
+ @message = message
46
+ end
47
+ opts.on("-d", "--subdir [SUBDIR]", String, "Sync just a subdir from the remote module.") do |subdir|
48
+ @module_options[:subdir] = subdir || ''
49
+ end
50
+ opts.on("-s", "--split", "Create a separate commit for each module.") do
51
+ @split = true
52
+ end
53
+ opts.on("-b", "--rebase", "Rebase after successful sync.") do
54
+ @rebase = true
55
+ end
56
+ end
57
+
58
+ def invoke()
59
+ helper = SyncHelper.new(project_git_dir, @logger)
60
+ if @manifest
61
+ helper.modules_from_manifest(@manifest)
62
+ elsif @create
63
+ local_path = ARGV.shift || "."
64
+ if helper.find_file_dir_in_workspace(local_path, RimInfo::InfoFileName)
65
+ raise RimException.new("There's already a module file. Don't use the create option to sync the module.")
66
+ elsif !@module_options[:remote_url] || !@module_options[:target_revision]
67
+ raise RimException.new("Please specify remote URL and target revision for the new module.")
68
+ else
69
+ helper.add_module_info(helper.create_module_info(
70
+ @module_options[:remote_url],
71
+ local_path,
72
+ @module_options[:target_revision],
73
+ @module_options[:ignores],
74
+ @module_options[:subdir],
75
+ ))
76
+ end
77
+ else
78
+ helper.modules_from_paths(@all ? helper.module_paths(ARGV, @excludedirs) : ARGV, @module_options)
79
+ end
80
+ helper.check_arguments
81
+ helper.sync(@message, @rebase, @split)
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+ end
88
+
89
+
@@ -1,143 +1,143 @@
1
- require 'rim/file_helper'
2
- require 'rim/processor'
3
- require 'rim/module_info'
4
- require 'rim/rim_info'
5
- require 'rim/manifest/json_reader'
6
- require 'rim/status_builder'
7
- require 'pathname'
8
-
9
- module RIM
10
-
11
- class CommandHelper < Processor
12
-
13
- include Manifest
14
-
15
- def initialize(workspace_root, logger, module_infos = nil)
16
- super(workspace_root, logger)
17
- @paths = []
18
- @logger = logger
19
- if module_infos
20
- module_infos.each do |m|
21
- add_module_info(m)
22
- end
23
- end
24
- end
25
-
26
- # check whether workspace is not touched
27
- def check_ready
28
- raise RimException.new("The workspace git contains uncommitted changes.") if !local_changes?(@ws_root)
29
- end
30
-
31
- def check_arguments
32
- raise RimException.new("Unexpected command line arguments.") if !ARGV.empty?
33
- end
34
-
35
- def create_module_info(remote_url, local_path, target_revision, ignores, subdir)
36
- ModuleInfo.new(
37
- remote_url,
38
- get_relative_path(local_path),
39
- target_revision,
40
- ignores,
41
- remote_url ? get_remote_branch_format(remote_url) : nil,
42
- subdir)
43
- end
44
-
45
- def modules_from_manifest(path)
46
- manifest = read_manifest(path)
47
- manifest.modules.each do |mod|
48
- add_unique_module_info(create_module_info(mod.remote_path, mod.local_path, mod.target_revision, mod.ignores, mod.subdir))
49
- end
50
- true
51
- end
52
-
53
- def modules_from_paths(paths, opts = {})
54
- if paths.empty?
55
- module_from_path(nil, opts)
56
- elsif paths.length == 1 || !opts.has_key?(:remote_url)
57
- while !paths.empty?
58
- module_from_path(paths.shift, opts)
59
- end
60
- else
61
- raise RimException.new("Multiple modules cannot be used with URL option.")
62
- end
63
- end
64
-
65
- def module_from_path(path, opts = {})
66
- module_path = find_file_dir_in_workspace(path || ".", RimInfo::InfoFileName)
67
- if module_path
68
- rim_info = RimInfo.from_dir(module_path)
69
- module_info = create_module_info(
70
- opts.has_key?(:remote_url) ? opts[:remote_url] : rim_info.remote_url,
71
- module_path,
72
- opts.has_key?(:target_revision) ? opts[:target_revision] : rim_info.target_revision,
73
- opts.has_key?(:ignores) ? opts[:ignores] : rim_info.ignores,
74
- opts.has_key?(:subdir) ? opts[:subdir] : rim_info.subdir)
75
- if module_info.valid?
76
- add_unique_module_info(module_info)
77
- module_path
78
- else
79
- raise RimException.new("Invalid .riminfo file found in directory '#{module_path}'.")
80
- end
81
- else
82
- raise RimException.new(path ? "No module info found in '#{path}'." : "No module info found.")
83
- end
84
- end
85
-
86
- def module_paths(paths, exclude_paths = nil)
87
- module_paths = []
88
- (paths.empty? ? ['.'] : paths).each do |p|
89
- module_paths.concat(all_module_paths_from_path(p))
90
- end
91
- paths.clear
92
- if exclude_paths
93
- exclude_paths.each do |e|
94
- all_module_paths_from_path(e).each do |p|
95
- module_paths.delete(p)
96
- end
97
- end
98
- end
99
- module_paths.sort
100
- end
101
-
102
- def all_module_paths_from_path(path)
103
- Dir.glob(File.join(path, "**/.riminfo")).map { |f| Pathname.new(File.expand_path(File.dirname(f))).relative_path_from(Pathname.pwd).to_s }
104
- end
105
-
106
- def add_unique_module_info(module_info)
107
- if !@paths.include?(module_info.local_path)
108
- @paths.push(module_info.local_path)
109
- add_module_info(module_info)
110
- else
111
- raise RimException.new("Module '#{module_info.local_path}' specified more than once.")
112
- end
113
- end
114
-
115
- def get_remote_branch_format(remote_url)
116
- get_absolute_remote_url(remote_url).start_with?(GerritServer) ? "refs/for/%s" : nil
117
- #"refs/for/%s"
118
- end
119
-
120
- def find_file_dir_in_workspace(start_dir, file)
121
- path = File.expand_path(start_dir)
122
- while path != @ws_root
123
- if File.exist?(File.join(path, file))
124
- return path
125
- else
126
- parent = File.dirname(path)
127
- if parent != path
128
- path = parent
129
- else
130
- break
131
- end
132
- end
133
- end
134
- nil
135
- end
136
-
137
- protected
138
- def add_module_info(module_info)
139
- end
140
-
141
- end
142
-
143
- end
1
+ require 'rim/file_helper'
2
+ require 'rim/processor'
3
+ require 'rim/module_info'
4
+ require 'rim/rim_info'
5
+ require 'rim/manifest/json_reader'
6
+ require 'rim/status_builder'
7
+ require 'pathname'
8
+
9
+ module RIM
10
+
11
+ class CommandHelper < Processor
12
+
13
+ include Manifest
14
+
15
+ def initialize(workspace_root, logger, module_infos = nil)
16
+ super(workspace_root, logger)
17
+ @paths = []
18
+ @logger = logger
19
+ if module_infos
20
+ module_infos.each do |m|
21
+ add_module_info(m)
22
+ end
23
+ end
24
+ end
25
+
26
+ # check whether workspace is not touched
27
+ def check_ready
28
+ raise RimException.new("The workspace git contains uncommitted changes.") if !local_changes?(@ws_root)
29
+ end
30
+
31
+ def check_arguments
32
+ raise RimException.new("Unexpected command line arguments.") if !ARGV.empty?
33
+ end
34
+
35
+ def create_module_info(remote_url, local_path, target_revision, ignores, subdir)
36
+ ModuleInfo.new(
37
+ remote_url,
38
+ get_relative_path(local_path),
39
+ target_revision,
40
+ ignores,
41
+ remote_url ? get_remote_branch_format(remote_url) : nil,
42
+ subdir)
43
+ end
44
+
45
+ def modules_from_manifest(path)
46
+ manifest = read_manifest(path)
47
+ manifest.modules.each do |mod|
48
+ add_unique_module_info(create_module_info(mod.remote_path, mod.local_path, mod.target_revision, mod.ignores, mod.subdir))
49
+ end
50
+ true
51
+ end
52
+
53
+ def modules_from_paths(paths, opts = {})
54
+ if paths.empty?
55
+ module_from_path(nil, opts)
56
+ elsif paths.length == 1 || !opts.has_key?(:remote_url)
57
+ while !paths.empty?
58
+ module_from_path(paths.shift, opts)
59
+ end
60
+ else
61
+ raise RimException.new("Multiple modules cannot be used with URL option.")
62
+ end
63
+ end
64
+
65
+ def module_from_path(path, opts = {})
66
+ module_path = find_file_dir_in_workspace(path || ".", RimInfo::InfoFileName)
67
+ if module_path
68
+ rim_info = RimInfo.from_dir(module_path)
69
+ module_info = create_module_info(
70
+ opts.has_key?(:remote_url) ? opts[:remote_url] : rim_info.remote_url,
71
+ module_path,
72
+ opts.has_key?(:target_revision) ? opts[:target_revision] : rim_info.target_revision,
73
+ opts.has_key?(:ignores) ? opts[:ignores] : rim_info.ignores,
74
+ opts.has_key?(:subdir) ? opts[:subdir] : rim_info.subdir)
75
+ if module_info.valid?
76
+ add_unique_module_info(module_info)
77
+ module_path
78
+ else
79
+ raise RimException.new("Invalid .riminfo file found in directory '#{module_path}'.")
80
+ end
81
+ else
82
+ raise RimException.new(path ? "No module info found in '#{path}'." : "No module info found.")
83
+ end
84
+ end
85
+
86
+ def module_paths(paths, exclude_paths = nil)
87
+ module_paths = []
88
+ (paths.empty? ? ['.'] : paths).each do |p|
89
+ module_paths.concat(all_module_paths_from_path(p))
90
+ end
91
+ paths.clear
92
+ if exclude_paths
93
+ exclude_paths.each do |e|
94
+ all_module_paths_from_path(e).each do |p|
95
+ module_paths.delete(p)
96
+ end
97
+ end
98
+ end
99
+ module_paths.sort
100
+ end
101
+
102
+ def all_module_paths_from_path(path)
103
+ Dir.glob(File.join(path, "**/.riminfo")).map { |f| Pathname.new(File.expand_path(File.dirname(f))).relative_path_from(Pathname.pwd).to_s }
104
+ end
105
+
106
+ def add_unique_module_info(module_info)
107
+ if !@paths.include?(module_info.local_path)
108
+ @paths.push(module_info.local_path)
109
+ add_module_info(module_info)
110
+ else
111
+ raise RimException.new("Module '#{module_info.local_path}' specified more than once.")
112
+ end
113
+ end
114
+
115
+ def get_remote_branch_format(remote_url)
116
+ get_absolute_remote_url(remote_url).start_with?(GerritServer) ? "refs/for/%s" : nil
117
+ #"refs/for/%s"
118
+ end
119
+
120
+ def find_file_dir_in_workspace(start_dir, file)
121
+ path = File.expand_path(start_dir)
122
+ while path != @ws_root
123
+ if File.exist?(File.join(path, file))
124
+ return path
125
+ else
126
+ parent = File.dirname(path)
127
+ if parent != path
128
+ path = parent
129
+ else
130
+ break
131
+ end
132
+ end
133
+ end
134
+ nil
135
+ end
136
+
137
+ protected
138
+ def add_module_info(module_info)
139
+ end
140
+
141
+ end
142
+
143
+ end