teuton 2.3.10 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -13
  3. data/docs/CHANGELOG.md +0 -13
  4. data/docs/changelog/todo.md +18 -0
  5. data/docs/changelog/v2.3.md +4 -0
  6. data/docs/changelog/v2.4.md +6 -2
  7. data/docs/dsl/execution/export.md +9 -15
  8. data/docs/dsl/execution/show.md +22 -7
  9. data/docs/ideas/{ideas.md → todo.md} +8 -16
  10. data/docs/learn/01-target.md +14 -43
  11. data/docs/learn/02-config.md +20 -37
  12. data/docs/learn/03-remote_hosts.md +20 -1
  13. data/docs/learn/04-new_test.md +4 -4
  14. data/docs/learn/05-use.md +3 -4
  15. data/docs/learn/06-debug.md +6 -9
  16. data/docs/learn/07-log.md +14 -14
  17. data/docs/learn/08-readme.md +4 -4
  18. data/docs/learn/13-include.md +13 -6
  19. data/docs/learn/14-alias.md +14 -8
  20. data/docs/learn/README.md +7 -7
  21. data/lib/teuton/case_manager/case/case.rb +1 -5
  22. data/lib/teuton/case_manager/case/dsl/expect.rb +2 -4
  23. data/lib/teuton/case_manager/case/dsl/log.rb +1 -2
  24. data/lib/teuton/case_manager/case/dsl/send.rb +4 -2
  25. data/lib/teuton/case_manager/case/play.rb +1 -2
  26. data/lib/teuton/case_manager/case/runner.rb +6 -7
  27. data/lib/teuton/case_manager/case_manager.rb +15 -11
  28. data/lib/teuton/case_manager/check_cases.rb +5 -7
  29. data/lib/teuton/case_manager/dsl.rb +9 -3
  30. data/lib/teuton/case_manager/export_manager.rb +13 -15
  31. data/lib/teuton/case_manager/hall_of_fame.rb +20 -16
  32. data/lib/teuton/case_manager/main.rb +1 -2
  33. data/lib/teuton/case_manager/report.rb +3 -3
  34. data/lib/teuton/report/formatter/base_formatter.rb +6 -7
  35. data/lib/teuton/report/formatter/{array_formatter.rb → default/array.rb} +44 -9
  36. data/lib/teuton/report/formatter/default/colored_text.rb +7 -0
  37. data/lib/teuton/report/formatter/default/html.rb +24 -0
  38. data/lib/teuton/report/formatter/default/json.rb +15 -0
  39. data/lib/teuton/report/formatter/{txt_formatter.rb → default/txt.rb} +4 -3
  40. data/lib/teuton/report/formatter/{xml_formatter.rb → default/xml.rb} +10 -4
  41. data/lib/teuton/report/formatter/default/yaml.rb +15 -0
  42. data/lib/teuton/report/formatter/formatter.rb +54 -0
  43. data/lib/teuton/report/formatter/moodle_csv_formatter.rb +4 -10
  44. data/lib/teuton/report/formatter/{resume_array_formatter.rb → resume/array.rb} +4 -7
  45. data/lib/teuton/report/formatter/resume/colored_text.rb +7 -0
  46. data/lib/teuton/report/formatter/{resume_html_formatter.rb → resume/html.rb} +7 -9
  47. data/lib/teuton/report/formatter/{resume_json_formatter.rb → resume/json.rb} +4 -4
  48. data/lib/teuton/report/formatter/{resume_txt_formatter.rb → resume/txt.rb} +4 -6
  49. data/lib/teuton/report/formatter/{resume_yaml_formatter.rb → resume/yaml.rb} +4 -3
  50. data/lib/teuton/report/report.rb +60 -43
  51. data/lib/teuton/report/show.rb +38 -24
  52. data/lib/teuton/version.rb +1 -1
  53. metadata +33 -34
  54. data/lib/teuton/case_manager/show.rb +0 -24
  55. data/lib/teuton/report/close.rb +0 -38
  56. data/lib/teuton/report/formatter/csv_formatter.rb +0 -25
  57. data/lib/teuton/report/formatter/formatter_factory.rb +0 -79
  58. data/lib/teuton/report/formatter/html_formatter.rb +0 -57
  59. data/lib/teuton/report/formatter/json_formatter.rb +0 -12
  60. data/lib/teuton/report/formatter/list_formatter.rb +0 -65
  61. data/lib/teuton/report/formatter/resume_list_formatter.rb +0 -62
  62. data/lib/teuton/report/formatter/yaml_formatter.rb +0 -15
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teuton
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.10
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Vargas Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-03 00:00:00.000000000 Z
11
+ date: 2022-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -30,70 +30,70 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.0'
33
+ version: '3.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.0'
40
+ version: '3.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: net-sftp
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.1'
47
+ version: '4.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.1'
54
+ version: '4.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: net-ssh
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '5.0'
61
+ version: '7.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '5.0'
68
+ version: '7.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: net-telnet
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.1'
75
+ version: '0.2'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.1'
82
+ version: '0.2'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: json_pure
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '2.2'
89
+ version: '2.6'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '2.2'
96
+ version: '2.6'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: thor
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '1.8'
117
+ version: '3.0'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '1.8'
124
+ version: '3.0'
125
125
  description: |2
126
126
  Intrastructure test, useful for:
127
127
  (1) Sysadmin teachers to evaluate students remote machines.
@@ -139,6 +139,7 @@ extra_rdoc_files:
139
139
  - README.md
140
140
  - LICENSE
141
141
  - docs/CHANGELOG.md
142
+ - docs/changelog/todo.md
142
143
  - docs/changelog/v2.0.md
143
144
  - docs/changelog/v2.1.md
144
145
  - docs/changelog/v2.2.md
@@ -165,8 +166,8 @@ extra_rdoc_files:
165
166
  - docs/es/guess_os.md
166
167
  - docs/ideas/Challenge-Server-Project.md
167
168
  - docs/ideas/contributions.md
168
- - docs/ideas/ideas.md
169
169
  - docs/ideas/servidor-de-retos.md
170
+ - docs/ideas/todo.md
170
171
  - docs/install/README.md
171
172
  - docs/install/manual.md
172
173
  - docs/install/modes_of_use.md
@@ -195,6 +196,7 @@ files:
195
196
  - README.md
196
197
  - bin/teuton
197
198
  - docs/CHANGELOG.md
199
+ - docs/changelog/todo.md
198
200
  - docs/changelog/v2.0.md
199
201
  - docs/changelog/v2.1.md
200
202
  - docs/changelog/v2.2.md
@@ -221,8 +223,8 @@ files:
221
223
  - docs/es/guess_os.md
222
224
  - docs/ideas/Challenge-Server-Project.md
223
225
  - docs/ideas/contributions.md
224
- - docs/ideas/ideas.md
225
226
  - docs/ideas/servidor-de-retos.md
227
+ - docs/ideas/todo.md
226
228
  - docs/install/README.md
227
229
  - docs/install/manual.md
228
230
  - docs/install/modes_of_use.md
@@ -280,7 +282,6 @@ files:
280
282
  - lib/teuton/case_manager/hall_of_fame.rb
281
283
  - lib/teuton/case_manager/main.rb
282
284
  - lib/teuton/case_manager/report.rb
283
- - lib/teuton/case_manager/show.rb
284
285
  - lib/teuton/case_manager/utils.rb
285
286
  - lib/teuton/check/builtin.rb
286
287
  - lib/teuton/check/dsl.rb
@@ -295,24 +296,22 @@ files:
295
296
  - lib/teuton/readme/dsl.rb
296
297
  - lib/teuton/readme/lang.rb
297
298
  - lib/teuton/readme/readme.rb
298
- - lib/teuton/report/close.rb
299
- - lib/teuton/report/formatter/array_formatter.rb
300
299
  - lib/teuton/report/formatter/base_formatter.rb
301
- - lib/teuton/report/formatter/csv_formatter.rb
302
- - lib/teuton/report/formatter/formatter_factory.rb
303
- - lib/teuton/report/formatter/html_formatter.rb
304
- - lib/teuton/report/formatter/json_formatter.rb
305
- - lib/teuton/report/formatter/list_formatter.rb
300
+ - lib/teuton/report/formatter/default/array.rb
301
+ - lib/teuton/report/formatter/default/colored_text.rb
302
+ - lib/teuton/report/formatter/default/html.rb
303
+ - lib/teuton/report/formatter/default/json.rb
304
+ - lib/teuton/report/formatter/default/txt.rb
305
+ - lib/teuton/report/formatter/default/xml.rb
306
+ - lib/teuton/report/formatter/default/yaml.rb
307
+ - lib/teuton/report/formatter/formatter.rb
306
308
  - lib/teuton/report/formatter/moodle_csv_formatter.rb
307
- - lib/teuton/report/formatter/resume_array_formatter.rb
308
- - lib/teuton/report/formatter/resume_html_formatter.rb
309
- - lib/teuton/report/formatter/resume_json_formatter.rb
310
- - lib/teuton/report/formatter/resume_list_formatter.rb
311
- - lib/teuton/report/formatter/resume_txt_formatter.rb
312
- - lib/teuton/report/formatter/resume_yaml_formatter.rb
313
- - lib/teuton/report/formatter/txt_formatter.rb
314
- - lib/teuton/report/formatter/xml_formatter.rb
315
- - lib/teuton/report/formatter/yaml_formatter.rb
309
+ - lib/teuton/report/formatter/resume/array.rb
310
+ - lib/teuton/report/formatter/resume/colored_text.rb
311
+ - lib/teuton/report/formatter/resume/html.rb
312
+ - lib/teuton/report/formatter/resume/json.rb
313
+ - lib/teuton/report/formatter/resume/txt.rb
314
+ - lib/teuton/report/formatter/resume/yaml.rb
316
315
  - lib/teuton/report/report.rb
317
316
  - lib/teuton/report/show.rb
318
317
  - lib/teuton/skeleton.rb
@@ -339,7 +338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
339
338
  - !ruby/object:Gem::Version
340
339
  version: '0'
341
340
  requirements: []
342
- rubygems_version: 3.3.26
341
+ rubygems_version: 3.2.33
343
342
  signing_key:
344
343
  specification_version: 4
345
344
  summary: Teuton (Infrastructure test)
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../application"
4
-
5
- # CaseManager show method
6
- class CaseManager
7
- ##
8
- # Show cases and resume report data on screep
9
- # @param mode (Symbol) Values => :resume, :cases or :all
10
- def show(mode = :resume)
11
- return if Application.instance.quiet?
12
-
13
- # Show resume report data on screen
14
- @report.show if %i[resume all].include? mode
15
-
16
- # Show cases report data on screen
17
- return if mode == :resume
18
-
19
- @cases.each do |c|
20
- puts "=" * 40
21
- c.show
22
- end
23
- end
24
- end
@@ -1,38 +0,0 @@
1
- class Report
2
- ##
3
- # Calculate final values:
4
- # * grade
5
- # * max_weight
6
- # * good_weight,d
7
- # * fail_weight
8
- # * fail_counter
9
- def close
10
- app = Application.instance
11
- max = 0.0
12
- good = 0.0
13
- fail = 0.0
14
- fail_counter = 0
15
- @lines.each do |i|
16
- next unless i.instance_of? Hash
17
-
18
- max += i[:weight] if i[:weight].positive?
19
- if i[:check]
20
- good += i[:weight]
21
- @history += app.letter[:good]
22
- else
23
- fail += i[:weight]
24
- fail_counter += 1
25
- @history += app.letter[:bad]
26
- end
27
- end
28
- @tail[:max_weight] = max
29
- @tail[:good_weight] = good
30
- @tail[:fail_weight] = fail
31
- @tail[:fail_counter] = fail_counter
32
-
33
- i = good.to_f / max
34
- i = 0 if i.nan?
35
- @tail[:grade] = (100.0 * i).round
36
- @tail[:grade] = 0 if @tail[:unique_fault].positive?
37
- end
38
- end
@@ -1,25 +0,0 @@
1
- require_relative "base_formatter"
2
-
3
- class CSVFormatter < BaseFormatter
4
- def process
5
- d = ";"
6
- @head.each { |key, value| w "HEAD#{d}#{key}#{d}#{value}\n" }
7
- @datagroups.each { |item| process_datagroup(item,d) }
8
- @tail.each { |key, value| w "TAIL#{d}#{key}#{d}#{value}\n" }
9
- deinit
10
- end
11
-
12
- def process_datagroup(group, delimiter = ";")
13
- d = delimiter
14
- a = "DATAGROUP#{group.order}#{d}"
15
- group.head.each { |key, value| w "#{a}HEAD#{d}#{key}#{d}#{value}\n" }
16
- group.lines.each do |i|
17
- if i.instance_of? Hash
18
- w "#{a}LINES#{d}ACTION#{d}#{i[:id]}#{d}#{i[:weight]}#{d}#{i[:description]}\n"
19
- else
20
- w "#{a}LINES#{d}LOG#{d}#{i}\n"
21
- end
22
- end
23
- group.tail.each { |key, value| w "#{a}TAIL#{d}#{key}#{d}#{value}\n" }
24
- end
25
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rainbow"
4
- require_relative "json_formatter"
5
- require_relative "html_formatter"
6
- require_relative "list_formatter"
7
- require_relative "txt_formatter"
8
- require_relative "yaml_formatter"
9
- require_relative "resume_json_formatter"
10
- require_relative "resume_html_formatter"
11
- require_relative "resume_list_formatter"
12
- require_relative "resume_yaml_formatter"
13
- require_relative "resume_txt_formatter"
14
- require_relative "moodle_csv_formatter"
15
- require_relative "csv_formatter"
16
- require_relative "xml_formatter"
17
-
18
- # FormaterFactory module
19
- module FormatterFactory
20
- def self.get(report, format, filename)
21
- case format
22
- when :colored_text
23
- f = TXTFormatter.new(report, true)
24
- when :csv
25
- f = CSVFormatter.new(report)
26
- when :html
27
- f = HTMLFormatter.new(report)
28
- when :json
29
- f = JSONFormatter.new(report)
30
- when :list
31
- f = ListFormatter.new(report)
32
- when :txt
33
- f = TXTFormatter.new(report, false)
34
- when :xml
35
- f = XMLFormatter.new(report)
36
- when :yaml
37
- f = YAMLFormatter.new(report)
38
- when :moodle_csv
39
- f = MoodleCSVFormatter.new(report)
40
- when :resume_txt
41
- f = ResumeTXTFormatter.new(report, false)
42
- when :resume_colored_text
43
- f = ResumeTXTFormatter.new(report, true)
44
- when :resume_json
45
- f = ResumeJSONFormatter.new(report)
46
- when :resume_html
47
- f = ResumeHTMLFormatter.new(report)
48
- when :resume_list
49
- f = ResumeListFormatter.new(report)
50
- when :resume_yaml
51
- f = ResumeYAMLFormatter.new(report)
52
- else
53
- raise "[ERROR] FormaterFactory #{format} unkown!"
54
- end
55
- f.init(filename)
56
- f
57
- end
58
-
59
- def self.ext(format)
60
- data = {
61
- cvs: "csv",
62
- colored_text: "txt",
63
- json: "json",
64
- list: "txt",
65
- txt: "txt",
66
- yaml: "yaml",
67
- resume_colored_text: "txt",
68
- resume_csv: "csv",
69
- resume_json: "json",
70
- resume_html: "html",
71
- resume_list: "txt",
72
- resume_txt: "txt",
73
- resume_yaml: "yaml"
74
- }
75
- return format.to_s if data[format].nil?
76
-
77
- data[format]
78
- end
79
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "erb"
4
- require_relative "yaml_formatter"
5
- require_relative "../../application"
6
-
7
- class HTMLFormatter < YAMLFormatter
8
- def initialize(report)
9
- super(report)
10
- @data = {}
11
- filepath = File.join(File.dirname(__FILE__), '..', '..', 'files', 'template', 'case.html')
12
- @template = File.read(filepath)
13
- end
14
-
15
- def process
16
- build_data
17
- build_page
18
- deinit
19
- end
20
-
21
- def build_page
22
- # config = @data[:config]
23
- # results = @data[:results]
24
- # logs = @data[:logs]
25
- # groups = @data[:groups]
26
- # hall_of_fame = @data[:hall_of_fame]
27
- # version = Application::VERSION
28
- render = ERB.new(@template)
29
- w render.result(binding)
30
- end
31
-
32
- private
33
-
34
- def config
35
- @data[:config]
36
- end
37
-
38
- def results
39
- @data[:results]
40
- end
41
-
42
- def logs
43
- @data[:logs]
44
- end
45
-
46
- def groups
47
- @data[:groups]
48
- end
49
-
50
- def hall_of_fame
51
- @data[:hall_of_fame]
52
- end
53
-
54
- def version
55
- Application::VERSION
56
- end
57
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json/pure"
4
- require_relative "array_formatter"
5
-
6
- class JSONFormatter < ArrayFormatter
7
- def process
8
- build_data
9
- w @data.to_json # Write data into ouput file
10
- deinit
11
- end
12
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "array_formatter"
4
-
5
- class ListFormatter < ArrayFormatter
6
- def process
7
- build_data
8
- process_config
9
- process_logs
10
- process_groups
11
- process_results
12
- process_hof
13
- deinit
14
- end
15
-
16
- private
17
-
18
- def process_config
19
- w "CONFIGURATION\n"
20
- @data[:config].sort.each { |key, value| w " * #{key} : #{value}\n" }
21
- w "\n\n"
22
- end
23
-
24
- def process_logs
25
- return if @data[:logs].size == 0
26
-
27
- w "\nLOGS\n"
28
- @data[:logs].each { |line| w " * #{line}\n" }
29
- end
30
-
31
- def process_groups
32
- return if @data[:groups].size == 0
33
-
34
- w "\nGROUPS\n"
35
- @data[:groups].each { |g| process_group g }
36
- end
37
-
38
- def process_results
39
- w "\nRESULTS\n"
40
- @data[:results].each do |key, value|
41
- w " * #{key} : #{value}\n"
42
- end
43
- end
44
-
45
- def process_hof
46
- return if @data[:hall_of_fame].size < 3
47
-
48
- w "\nHALL OF FAME\n"
49
- @data[:hall_of_fame].each do |line|
50
- w " #{line[0]} #{line[1]}\n"
51
- end
52
- end
53
-
54
- private
55
-
56
- def process_group(group)
57
- tab = " "
58
- w "- #{group[:title]}\n"
59
- group[:targets].each do |i|
60
- w "#{tab * 2}#{format("%02d", i[:target_id].to_i)}"
61
- w " (#{i[:score]}/#{i[:weight]}) "
62
- w "#{i[:description]}\n"
63
- end
64
- end
65
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "resume_array_formatter"
4
-
5
- # ResumeListFormatter class
6
- class ResumeListFormatter < ResumeArrayFormatter
7
- def initialize(report)
8
- super(report)
9
- @data = {}
10
- end
11
-
12
- def process
13
- build_data
14
- process_config
15
- process_cases
16
- process_conn_errors
17
- process_results
18
- process_hof
19
- deinit
20
- end
21
-
22
- private
23
-
24
- def process_config
25
- w "CONFIGURATION\n"
26
- @data[:config].each do |key, value|
27
- w " * #{key}: #{trim(value)}\n"
28
- end
29
- end
30
-
31
- def process_cases
32
- w "CASES\n"
33
- @data[:cases].each do |line|
34
- w " [#{line[:id]}] #{line[:members]} :#{format("%3d", line[:grade])}\n"
35
- end
36
- end
37
-
38
- def process_conn_errors
39
- w "CONN ERRORS\n"
40
- @data[:cases].each do |line|
41
- line[:conn_status].each_pair do |h, e|
42
- w " * #{line[:id]} #{line[:members]} #{h} #{e}\n"
43
- end
44
- end
45
- end
46
-
47
- def process_results
48
- w "\nRESULTS\n"
49
- @data[:results].each do |key, value|
50
- w " * #{key}: #{value}\n"
51
- end
52
- end
53
-
54
- def process_hof
55
- return if @data[:hall_of_fame].size < 3
56
-
57
- w "\nHALL OF FAME\n"
58
- @data[:hall_of_fame].each do |line|
59
- w " #{line[0]} : #{line[1]}\n"
60
- end
61
- end
62
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "yaml"
4
- require_relative "array_formatter"
5
-
6
- class YAMLFormatter < ArrayFormatter
7
- ##
8
- # Process data from parent object and export it into YAML format.
9
- # @return [nil]
10
- def process
11
- build_data
12
- w @data.to_yaml # Write data into ouput file
13
- deinit
14
- end
15
- end