ievkit_views 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +4 -0
- data/Rakefile +37 -0
- data/app/assets/javascripts/ievkit_views/application.js +17 -0
- data/app/assets/stylesheets/ievkit_views/application.css +4 -0
- data/app/assets/stylesheets/ievkit_views/report_results.scss +76 -0
- data/app/controllers/ievkit_views/application_controller.rb +5 -0
- data/app/helpers/ievkit_views/application_helper.rb +32 -0
- data/app/services/ievkit_views/action_report.rb +86 -0
- data/app/services/ievkit_views/report.rb +104 -0
- data/app/services/ievkit_views/validation_report.rb +37 -0
- data/app/services/ievkit_views/validation_service.rb +253 -0
- data/app/views/ievkit_views/_element_count.html.erb +3 -0
- data/app/views/ievkit_views/_file_details.html.erb +13 -0
- data/app/views/ievkit_views/_paginate.html.erb +1 -0
- data/app/views/ievkit_views/_report.html.erb +33 -0
- data/app/views/ievkit_views/_report_badges.html.erb +80 -0
- data/app/views/ievkit_views/_report_filters.html.erb +34 -0
- data/app/views/ievkit_views/_report_links.html.erb +31 -0
- data/app/views/ievkit_views/_report_results.html.erb +58 -0
- data/app/views/ievkit_views/_report_results_error_name.html.erb +1 -0
- data/app/views/ievkit_views/_report_results_files.html.erb +41 -0
- data/app/views/ievkit_views/_report_results_tests.html.erb +38 -0
- data/app/views/ievkit_views/_report_results_transport_datas.html.erb +47 -0
- data/config/initializers/numeric.rb +5 -0
- data/config/routes.rb +2 -0
- data/lib/ievkit_views/engine.rb +5 -0
- data/lib/ievkit_views/version.rb +3 -0
- data/lib/ievkit_views.rb +4 -0
- data/lib/tasks/ievkit_views_tasks.rake +4 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +30 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/log/development.log +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/ievkit_views_test.rb +7 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/test_helper.rb +21 -0
- metadata +206 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fea119828d0d0905ecb3949dd80945bbd46a0d57
|
4
|
+
data.tar.gz: 8e834dcf39f1c06085c48885b66dbf57029c5caa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8460180deba82dbff3f35d95793611579e075bb17f3e8835c3fb65d1ae0767d108cfcb5966677b42c954f00d468dd454f6f2a95479006c3b966f56470b914fe9
|
7
|
+
data.tar.gz: 88c769e4b488d4aec1f551cbb15567d819bf19ecd2b183539660d57e9ba949e17f9c10b3dc905b5fe9426cdeffb4ac35cf6b6cbf57f3332682f2c5ac8530632f
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Bruno Perles
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'IevkitViews'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
task default: :test
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
(function($){
|
4
|
+
$(document).on('page:change', function () {
|
5
|
+
$('.ievkit-AccordionBlock-details').click( function() {
|
6
|
+
var $gi = $(this).find('.glyphicon');
|
7
|
+
$gi.toggleClass('glyphicon-plus glyphicon-minus');
|
8
|
+
$(this).closest('li').find('div').slideToggle();
|
9
|
+
});
|
10
|
+
$('[data-toggle="collapse"]').click( function() {
|
11
|
+
var index = parseInt($(this).data('jump-to'));
|
12
|
+
if(index > 4) {
|
13
|
+
window.location.href = '#heading-' + (index - 4);
|
14
|
+
}
|
15
|
+
});
|
16
|
+
});
|
17
|
+
})(jQuery);
|
@@ -0,0 +1,76 @@
|
|
1
|
+
.ievkit {
|
2
|
+
&-AccordionBlock {
|
3
|
+
ul {
|
4
|
+
margin: 0;
|
5
|
+
padding: 0;
|
6
|
+
ul {
|
7
|
+
padding-left: 31px;
|
8
|
+
}
|
9
|
+
}
|
10
|
+
li {
|
11
|
+
list-style: none;
|
12
|
+
}
|
13
|
+
/*
|
14
|
+
.panel-title {
|
15
|
+
> a {
|
16
|
+
display: block;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
*/
|
20
|
+
&-details {
|
21
|
+
border: none;
|
22
|
+
background: none;
|
23
|
+
}
|
24
|
+
&-errorInfo {
|
25
|
+
font-style: italic;
|
26
|
+
font-size: smaller;
|
27
|
+
}
|
28
|
+
&-errorId {
|
29
|
+
margin: 0 0 0 19px;
|
30
|
+
font-weight: bold;
|
31
|
+
&-detail {
|
32
|
+
margin: 0 0 0 19px;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
&-ColorBlock {
|
37
|
+
&-ok, &-ok-sign {
|
38
|
+
color: green;
|
39
|
+
}
|
40
|
+
&-ignored {
|
41
|
+
color: #000;
|
42
|
+
}
|
43
|
+
&-alert, &-warning-sign {
|
44
|
+
color: orange;
|
45
|
+
}
|
46
|
+
&-remove, &-minus-sign {
|
47
|
+
color: red;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
&-BgColorBlock {
|
51
|
+
&-ok, &-ok-sign {
|
52
|
+
background-color: green !important;
|
53
|
+
}
|
54
|
+
&-ignored {
|
55
|
+
background-color: #000 !important;
|
56
|
+
}
|
57
|
+
&-alert {
|
58
|
+
background-color: orange !important;
|
59
|
+
}
|
60
|
+
&-remove, &-minus-sign {
|
61
|
+
background-color: red !important;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
&-SearchBlock {
|
65
|
+
margin: 20px 0;
|
66
|
+
background-color: #eee;
|
67
|
+
padding: 8px 16px;
|
68
|
+
border: 1px solid #ddd;
|
69
|
+
&-search {
|
70
|
+
margin-right: 20px;
|
71
|
+
}
|
72
|
+
input[type=search] {
|
73
|
+
width: 200px;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module IevkitViews
|
2
|
+
module ApplicationHelper
|
3
|
+
def badge_count(datas, type = nil, *status)
|
4
|
+
datas = datas.select{ |d| status.include? d[:status] }
|
5
|
+
type ? datas.count{ |d| d[:type] == type } : datas.count
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_icon(name, count_error = 0, count_warning = 0)
|
9
|
+
return 'question-sign' unless name.present?
|
10
|
+
name = name.to_sym.downcase
|
11
|
+
if name == :error && count_error > 0
|
12
|
+
'minus-sign'
|
13
|
+
elsif name == :warning || (count_warning > 0 && name != :ignored)
|
14
|
+
'warning-sign'
|
15
|
+
elsif name == :ignored
|
16
|
+
'ban-circle'
|
17
|
+
else
|
18
|
+
'ok-sign'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_icon_title(name, count_error = 0, count_warning = 0)
|
23
|
+
name = name.to_sym.downcase
|
24
|
+
fs_status = if (count_warning > 0 && name != :ignored)
|
25
|
+
'warning'
|
26
|
+
else
|
27
|
+
name.to_s
|
28
|
+
end
|
29
|
+
I18n.t("report.icons.#{fs_status.downcase}_txt", default: fs_status.to_s.humanize)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module IevkitViews
|
2
|
+
class ActionReport < Report
|
3
|
+
|
4
|
+
def progression
|
5
|
+
progression = @report['progression']
|
6
|
+
return {} unless progression
|
7
|
+
index_current_step = progression['current_step'].to_i - 1
|
8
|
+
@datas = {
|
9
|
+
current_step: progression['current_step'].to_i,
|
10
|
+
steps_count: progression['steps_count'].to_i,
|
11
|
+
current_step_realized: progression['steps'][index_current_step]['realized'].to_i,
|
12
|
+
current_step_total: progression['steps'][index_current_step]['total'].to_i
|
13
|
+
}.tap{ |hash|
|
14
|
+
hash[:steps_percent] = hash[:current_step].percent_of(hash[:steps_count]).round(2)
|
15
|
+
hash[:current_step_percent] = hash[:current_step_realized].percent_of(hash[:current_step_total]).round(2)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def files
|
20
|
+
datas = []
|
21
|
+
return datas unless @report['files']
|
22
|
+
@report['files'].each do |d|
|
23
|
+
next unless d['name']
|
24
|
+
datas << {
|
25
|
+
name: d['name'],
|
26
|
+
type: d['type'],
|
27
|
+
status: d['status']&.downcase&.to_sym,
|
28
|
+
count_error: d['check_point_error_count'].to_i,
|
29
|
+
count_warning: d['check_point_warning_count'].to_i,
|
30
|
+
check_point_errors: d['check_point_errors']
|
31
|
+
}.tap{ |hash|
|
32
|
+
hash[:error_or_warning] = (hash[:count_error] + hash[:count_warning]) > 0
|
33
|
+
}
|
34
|
+
end
|
35
|
+
return sort_datas(datas)
|
36
|
+
#search_for(datas)
|
37
|
+
end
|
38
|
+
|
39
|
+
def objects(type = nil)
|
40
|
+
datas = []
|
41
|
+
return datas unless @report['objects']
|
42
|
+
@report['objects'].each do |d|
|
43
|
+
next unless d['type']
|
44
|
+
next if type && type != d['type']
|
45
|
+
datas << {
|
46
|
+
name: d['type'] != 'line' ? I18n.t("report.default_view.#{d['type']}") : d['description'],
|
47
|
+
type: d['type'],
|
48
|
+
status: d['status']&.downcase&.to_sym,
|
49
|
+
count_error: d['check_point_error_count'].to_i,
|
50
|
+
count_warning: d['check_point_warning_count'].to_i,
|
51
|
+
check_point_errors: d['check_point_errors']
|
52
|
+
}.tap{ |hash|
|
53
|
+
hash[:error_or_warning] = (hash[:count_error] + hash[:count_warning]) > 0
|
54
|
+
}
|
55
|
+
end
|
56
|
+
return sort_datas(datas)
|
57
|
+
# search_for(datas)
|
58
|
+
end
|
59
|
+
|
60
|
+
def collections(type = 'line')
|
61
|
+
datas = []
|
62
|
+
return datas unless @report['collections'].present?
|
63
|
+
collections = []
|
64
|
+
@report['collections'].each{ |el|
|
65
|
+
collections << el['objects'] if el['type'] == type
|
66
|
+
}
|
67
|
+
collections.flatten!
|
68
|
+
return datas unless collections.count > 0
|
69
|
+
collections.each do |d|
|
70
|
+
next unless d['description']
|
71
|
+
datas << {
|
72
|
+
name: d['type'] != 'line' ? I18n.t("report.default_view.#{d['type']}") : d['description'],
|
73
|
+
type: d['type'],
|
74
|
+
status: d['status']&.downcase&.to_sym,
|
75
|
+
count_error: d['check_point_error_count'].to_i,
|
76
|
+
count_warning: d['check_point_warning_count'].to_i,
|
77
|
+
check_point_errors: d['check_point_errors']
|
78
|
+
}.tap{ |hash|
|
79
|
+
hash[:error_or_warning] = (hash[:count_error] + hash[:count_warning]) > 0
|
80
|
+
}
|
81
|
+
end
|
82
|
+
return sort_datas(datas)
|
83
|
+
# search_for(datas)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module IevkitViews
|
2
|
+
class Report
|
3
|
+
|
4
|
+
include IevkitViews::ApplicationHelper
|
5
|
+
attr_reader :result, :datas, :search
|
6
|
+
|
7
|
+
def initialize(referential, link_action, type_report, link_validation = nil, search = nil)
|
8
|
+
@datas = {}
|
9
|
+
@result = :error
|
10
|
+
ievkit = ::Ievkit::Job.new(referential)
|
11
|
+
report = ievkit.get_job(link_action)
|
12
|
+
@report = report[type_report] if report
|
13
|
+
@validation = link_validation ? ievkit.get_job(link_validation) : nil
|
14
|
+
if @validation && @validation['validation_report'] && @validation['validation_report']['result']
|
15
|
+
@result = @validation['validation_report']['result'].downcase.to_sym
|
16
|
+
end
|
17
|
+
@search = search
|
18
|
+
end
|
19
|
+
|
20
|
+
def sort_datas(datas)
|
21
|
+
sorted_by = { error: [], warning: [], ok: [], ignored: [], '': [] }
|
22
|
+
datas.flatten.each{ |d|
|
23
|
+
sorted_by[d[:status]] << d
|
24
|
+
}
|
25
|
+
sorted_by.each{ |key, value|
|
26
|
+
sorted_by[key] = value.sort_by{ |a| [a[:count_error], a[:count_warning]] }.reverse
|
27
|
+
}
|
28
|
+
[].tap{ |a|
|
29
|
+
a << sorted_by.map{ |_k, v| v }
|
30
|
+
}.flatten!
|
31
|
+
end
|
32
|
+
|
33
|
+
def search_for(datas)
|
34
|
+
return datas unless search.present? && datas.present?
|
35
|
+
files = []
|
36
|
+
files << datas.select{ |value| value.to_s.downcase =~/#{search.downcase}/i }
|
37
|
+
files.flatten!
|
38
|
+
end
|
39
|
+
|
40
|
+
def sum_report(datas)
|
41
|
+
return {} unless datas.present?
|
42
|
+
{}.tap{ |hash|
|
43
|
+
datas.map{ |el| el[:type] }.uniq.each do |type|
|
44
|
+
hash[type] = {
|
45
|
+
ok: badge_count(datas, type, :ok),
|
46
|
+
error: badge_count(datas, type, :error, :warning),
|
47
|
+
ignored: badge_count(datas, type, :ignored)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def sum_report_for_tests(datas)
|
54
|
+
return {} unless datas.present?
|
55
|
+
{}.tap{ |hash|
|
56
|
+
hash['tests-1-2-error'] = { ok: 0, error: 0, ignored: 0 }
|
57
|
+
hash['tests-1-2-warning'] = { ok: 0, error: 0, ignored: 0 }
|
58
|
+
hash['tests-3-4-error'] = { ok: 0, error: 0, ignored: 0 }
|
59
|
+
hash['tests-3-4-warning'] = { ok: 0, error: 0, ignored: 0 }
|
60
|
+
datas.each do |d|
|
61
|
+
severity = d[:severity] == :error ? :error : :warning
|
62
|
+
status = d[:status] == :warning ? :error : d[:status]
|
63
|
+
hash["tests-1-2-#{severity}"][status] += 1 if %w(1 2).include? d[:name][0]
|
64
|
+
hash["tests-3-4-#{severity}"][status] += 1 if %w(3 4).include? d[:name][0]
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def errors
|
70
|
+
clean_errors = []
|
71
|
+
return clean_errors unless @validation
|
72
|
+
errors = @validation['validation_report']['errors']
|
73
|
+
return clean_errors unless errors
|
74
|
+
errors.each do |error|
|
75
|
+
error = key_to_sym(error)
|
76
|
+
error[:source_label] = error[:source][:label]
|
77
|
+
error[:source_objectid] = error[:source][:objectid]
|
78
|
+
error[:filename] = error[:source][:file][:filename] if error[:source][:file]
|
79
|
+
if error[:target]
|
80
|
+
error[:target].each_with_index do |target, index|
|
81
|
+
target = key_to_sym(target)
|
82
|
+
error[:target][index] = target
|
83
|
+
error[:"target_#{index}_label"] = target[:label]
|
84
|
+
error[:"target_#{index}_objectid"] = target[:objectid]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
error[:test_name] = I18n.t("compliance_check_results.details.#{error[:test_id]}")
|
88
|
+
error[:error_name] = I18n.t("compliance_check_results.details.detail_#{error[:error_id]}", error)
|
89
|
+
clean_errors << error
|
90
|
+
end
|
91
|
+
clean_errors
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def key_to_sym(el)
|
97
|
+
return el unless el.is_a? Hash
|
98
|
+
Hash[el.map { |k, v| [
|
99
|
+
k.to_sym, key_to_sym(v)
|
100
|
+
] }]
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module IevkitViews
|
2
|
+
class ValidationReport < Report
|
3
|
+
def check_points
|
4
|
+
datas = []
|
5
|
+
return datas unless @report && @report['check_points']
|
6
|
+
@report['check_points'].each do |d|
|
7
|
+
next unless d['test_id']
|
8
|
+
severity =d['severity']&.downcase&.to_sym
|
9
|
+
result = d['result']&.downcase&.to_sym
|
10
|
+
status = if severity == :error && result == :nok
|
11
|
+
:error
|
12
|
+
elsif severity == :warning && result == :nok
|
13
|
+
:warning
|
14
|
+
elsif result == :uncheck
|
15
|
+
:ignored
|
16
|
+
else
|
17
|
+
:ok
|
18
|
+
end
|
19
|
+
check_point_error_count = d['check_point_error_count'].to_i
|
20
|
+
count_error = status == :error ? check_point_error_count : 0
|
21
|
+
count_warning = status == :warning ? check_point_error_count : 0
|
22
|
+
datas << {
|
23
|
+
name: d['test_id'],
|
24
|
+
type: d['type'],
|
25
|
+
status: status,
|
26
|
+
severity: severity,
|
27
|
+
count_error: count_error,
|
28
|
+
count_warning: count_warning,
|
29
|
+
check_point_errors: d['errors']
|
30
|
+
}.tap{ |hash|
|
31
|
+
hash[:error_or_warning] = (hash[:count_error] + hash[:count_warning]) > 0
|
32
|
+
}
|
33
|
+
end
|
34
|
+
sort_datas(datas)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|