pact_broker 1.14.0 → 1.15.0
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/.travis.yml +1 -0
- data/CHANGELOG.md +11 -0
- data/LICENSE.txt +2 -0
- data/README.md +6 -2
- data/example/Gemfile +3 -3
- data/lib/pact_broker.rb +6 -1
- data/lib/pact_broker/api.rb +8 -1
- data/lib/pact_broker/api/contracts/pacticipant_name_contract.rb +2 -4
- data/lib/pact_broker/api/contracts/put_pact_params_contract.rb +25 -32
- data/lib/pact_broker/api/contracts/request_validations.rb +5 -11
- data/lib/pact_broker/api/contracts/webhook_contract.rb +28 -15
- data/lib/pact_broker/api/decorators/versions_decorator.rb +41 -0
- data/lib/pact_broker/api/resources/base_resource.rb +7 -3
- data/lib/pact_broker/api/resources/latest_pact.rb +1 -1
- data/lib/pact_broker/api/resources/latest_pacts.rb +2 -2
- data/lib/pact_broker/api/resources/latest_provider_pacts.rb +1 -1
- data/lib/pact_broker/api/resources/pact.rb +2 -2
- data/lib/pact_broker/api/resources/pact_content_diff.rb +2 -5
- data/lib/pact_broker/api/resources/pact_versions.rb +1 -1
- data/lib/pact_broker/api/resources/pact_webhooks.rb +8 -5
- data/lib/pact_broker/api/resources/pacticipant.rb +1 -1
- data/lib/pact_broker/api/resources/pacticipants.rb +2 -2
- data/lib/pact_broker/api/resources/tag.rb +2 -2
- data/lib/pact_broker/api/resources/version.rb +1 -1
- data/lib/pact_broker/api/resources/versions.rb +34 -0
- data/lib/pact_broker/api/resources/webhook.rb +2 -2
- data/lib/pact_broker/api/resources/webhook_execution.rb +1 -1
- data/lib/pact_broker/domain/version.rb +4 -0
- data/lib/pact_broker/domain/webhook.rb +2 -0
- data/lib/pact_broker/locale/en.yml +9 -1
- data/lib/pact_broker/pacts/diff.rb +26 -27
- data/lib/pact_broker/repositories/pacticipant_repository.rb +7 -0
- data/lib/pact_broker/services/pacticipant_service.rb +4 -0
- data/lib/pact_broker/services/webhook_service.rb +2 -2
- data/lib/pact_broker/version.rb +1 -1
- data/pact_broker.gemspec +4 -6
- data/spec/features/get_versions_spec.rb +36 -0
- data/spec/lib/pact_broker/api/contracts/put_pact_params_contract_spec.rb +12 -19
- data/spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb +7 -9
- data/spec/lib/pact_broker/api/decorators/embedded_tag_decorator_spec.rb +2 -2
- data/spec/lib/pact_broker/api/decorators/embedded_version_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/latest_pact_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/pact_decorator_spec.rb +2 -2
- data/spec/lib/pact_broker/api/decorators/pact_version_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/tag_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/versions_decorator_spec.rb +44 -0
- data/spec/lib/pact_broker/api/decorators/webhook_decorator_spec.rb +35 -39
- data/spec/lib/pact_broker/api/decorators/webhook_execution_result_decorator_spec.rb +2 -2
- data/spec/lib/pact_broker/api/decorators/webhooks_decorator_spec.rb +2 -2
- data/spec/lib/pact_broker/api/resources/pact_spec.rb +2 -3
- data/spec/lib/pact_broker/api/resources/pact_webhooks_spec.rb +3 -3
- data/spec/lib/pact_broker/api/resources/tag_spec.rb +2 -2
- data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +1 -1
- data/spec/lib/pact_broker/api/resources/webhook_spec.rb +1 -1
- data/spec/lib/pact_broker/pacts/diff_spec.rb +1 -1
- metadata +28 -22
@@ -5,9 +5,7 @@ require 'pact_broker/pacts/diff'
|
|
5
5
|
module PactBroker
|
6
6
|
module Api
|
7
7
|
module Resources
|
8
|
-
|
9
8
|
class PactContentDiff < BaseResource
|
10
|
-
|
11
9
|
def content_types_provided
|
12
10
|
[["text/plain", :to_text]]
|
13
11
|
end
|
@@ -22,8 +20,8 @@ module PactBroker
|
|
22
20
|
end
|
23
21
|
|
24
22
|
def to_text
|
25
|
-
|
26
|
-
response.body =
|
23
|
+
output = PactBroker::Pacts::Diff.new.process pact_params.merge(base_url: base_url)
|
24
|
+
response.body = output
|
27
25
|
end
|
28
26
|
|
29
27
|
def pact
|
@@ -33,7 +31,6 @@ module PactBroker
|
|
33
31
|
def pact_params
|
34
32
|
@pact_params ||= PactBroker::Pacts::PactParams.from_request request, path_info
|
35
33
|
end
|
36
|
-
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
@@ -22,7 +22,7 @@ module PactBroker
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_json
|
25
|
-
PactBroker::Api::Decorators::PactVersionsDecorator.new(pacts).to_json(decorator_context(identifier_from_path))
|
25
|
+
PactBroker::Api::Decorators::PactVersionsDecorator.new(pacts).to_json(user_options: decorator_context(identifier_from_path))
|
26
26
|
end
|
27
27
|
|
28
28
|
def pacts
|
@@ -35,11 +35,14 @@ module PactBroker
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def validation_errors? webhook
|
38
|
-
|
38
|
+
errors = webhook_service.errors(webhook)
|
39
|
+
|
40
|
+
unless errors.empty?
|
39
41
|
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
40
|
-
response.body = {errors: errors.
|
42
|
+
response.body = { errors: errors.messages }.to_json
|
41
43
|
end
|
42
|
-
|
44
|
+
|
45
|
+
!errors.empty?
|
43
46
|
end
|
44
47
|
|
45
48
|
def create_path
|
@@ -52,11 +55,11 @@ module PactBroker
|
|
52
55
|
|
53
56
|
def from_json
|
54
57
|
saved_webhook = webhook_service.create next_uuid, webhook, consumer, provider
|
55
|
-
response.body = Decorators::WebhookDecorator.new(saved_webhook).to_json(base_url: base_url)
|
58
|
+
response.body = Decorators::WebhookDecorator.new(saved_webhook).to_json(user_options: { base_url: base_url })
|
56
59
|
end
|
57
60
|
|
58
61
|
def to_json
|
59
|
-
Decorators::WebhooksDecorator.new(webhooks).to_json(decorator_context(resource_title: 'Pact webhooks'))
|
62
|
+
Decorators::WebhooksDecorator.new(webhooks).to_json(user_options: decorator_context(resource_title: 'Pact webhooks'))
|
60
63
|
end
|
61
64
|
|
62
65
|
private
|
@@ -50,7 +50,7 @@ module PactBroker
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def to_json
|
53
|
-
PactBroker::Api::Decorators::PacticipantDecorator.new(pacticipant).to_json(base_url: base_url)
|
53
|
+
PactBroker::Api::Decorators::PacticipantDecorator.new(pacticipant).to_json(user_options: { base_url: base_url })
|
54
54
|
end
|
55
55
|
|
56
56
|
private
|
@@ -45,7 +45,7 @@ module PactBroker
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def generate_json pacticipants
|
48
|
-
PactBroker::Api::Decorators::PacticipantCollectionDecorator.new(pacticipants).to_json(base_url: base_url)
|
48
|
+
PactBroker::Api::Decorators::PacticipantCollectionDecorator.new(pacticipants).to_json(user_options: { base_url: base_url })
|
49
49
|
end
|
50
50
|
|
51
51
|
def decorator_for model
|
@@ -60,4 +60,4 @@ module PactBroker
|
|
60
60
|
end
|
61
61
|
|
62
62
|
end
|
63
|
-
end
|
63
|
+
end
|
@@ -32,7 +32,7 @@ module PactBroker
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def to_json
|
35
|
-
PactBroker::Api::Decorators::TagDecorator.new(tag).to_json(base_url: base_url)
|
35
|
+
PactBroker::Api::Decorators::TagDecorator.new(tag).to_json(user_options: { base_url: base_url })
|
36
36
|
end
|
37
37
|
|
38
38
|
def tag
|
@@ -48,4 +48,4 @@ module PactBroker
|
|
48
48
|
end
|
49
49
|
|
50
50
|
end
|
51
|
-
end
|
51
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pact_broker/api/resources/base_resource'
|
2
|
+
require 'pact_broker/configuration'
|
3
|
+
require 'pact_broker/api/decorators/versions_decorator'
|
4
|
+
|
5
|
+
module PactBroker
|
6
|
+
module Api
|
7
|
+
module Resources
|
8
|
+
|
9
|
+
class Versions < BaseResource
|
10
|
+
|
11
|
+
def content_types_provided
|
12
|
+
[["application/json", :to_json]]
|
13
|
+
end
|
14
|
+
|
15
|
+
def allowed_methods
|
16
|
+
["GET"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def resource_exists?
|
20
|
+
pacticipant_service.find_pacticipant_by_name(pacticipant_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_json
|
24
|
+
PactBroker::Api::Decorators::VersionsDecorator.new(versions).to_json(user_options: decorator_context(identifier_from_path))
|
25
|
+
end
|
26
|
+
|
27
|
+
def versions
|
28
|
+
pacticipant_service.find_all_pacticipant_versions pacticipant_name
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -20,7 +20,7 @@ module PactBroker
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def to_json
|
23
|
-
Decorators::WebhookDecorator.new(webhook).to_json(base_url: base_url)
|
23
|
+
Decorators::WebhookDecorator.new(webhook).to_json(user_options: { base_url: base_url })
|
24
24
|
end
|
25
25
|
|
26
26
|
def delete_resource
|
@@ -42,4 +42,4 @@ module PactBroker
|
|
42
42
|
end
|
43
43
|
|
44
44
|
end
|
45
|
-
end
|
45
|
+
end
|
@@ -25,7 +25,7 @@ module PactBroker
|
|
25
25
|
private
|
26
26
|
|
27
27
|
def post_response_body webhook_execution_result
|
28
|
-
Decorators::WebhookExecutionResultDecorator.new(webhook_execution_result).to_json(base_url: base_url, webhook: webhook)
|
28
|
+
Decorators::WebhookExecutionResultDecorator.new(webhook_execution_result).to_json(user_options: { base_url: base_url, webhook: webhook })
|
29
29
|
end
|
30
30
|
|
31
31
|
def webhook
|
@@ -19,6 +19,10 @@ module PactBroker
|
|
19
19
|
def to_s
|
20
20
|
"Version: number=#{number}, pacticipant=#{pacticipant_id}"
|
21
21
|
end
|
22
|
+
|
23
|
+
def version_and_updated_date
|
24
|
+
"Version #{number} - #{updated_at.to_time.localtime.strftime("%d/%m/%Y")}"
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
Version.plugin :timestamps, :update_on_create=>true
|
@@ -13,8 +13,10 @@ module PactBroker
|
|
13
13
|
include Logging
|
14
14
|
|
15
15
|
attr_accessor :uuid, :consumer, :provider, :request, :created_at, :updated_at
|
16
|
+
attr_reader :attributes
|
16
17
|
|
17
18
|
def initialize attributes = {}
|
19
|
+
@attributes = attributes
|
18
20
|
@uuid = attributes[:uuid]
|
19
21
|
@request = attributes[:request]
|
20
22
|
@consumer = attributes[:consumer]
|
@@ -1,4 +1,12 @@
|
|
1
1
|
en:
|
2
|
+
errors:
|
3
|
+
filled?: "can't be blank"
|
4
|
+
valid_method?: "is not a recognised HTTP method"
|
5
|
+
valid_url?: "is not a valid URL eg. http://example.org"
|
6
|
+
|
7
|
+
name_in_path_matches_name_in_pact?: "does not match %{left} name in path ('%{right}')."
|
8
|
+
valid_consumer_version_number?: "Consumer version number '%{value}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
|
9
|
+
|
2
10
|
pact_broker:
|
3
11
|
errors:
|
4
12
|
validation:
|
@@ -70,4 +78,4 @@ en:
|
|
70
78
|
other: "over %{count} years"
|
71
79
|
almost_x_years:
|
72
80
|
one: "almost 1 year"
|
73
|
-
other: "almost %{count} years"
|
81
|
+
other: "almost %{count} years"
|
@@ -1,39 +1,39 @@
|
|
1
|
-
require 'trailblazer/operation'
|
2
|
-
require 'pact_broker/repositories'
|
3
|
-
require 'pact_broker/pacts/create_formatted_diff'
|
4
1
|
require 'pact_broker/api/pact_broker_urls'
|
5
|
-
require 'yaml'
|
6
2
|
require 'pact_broker/date_helper'
|
7
|
-
|
3
|
+
require 'pact_broker/pacts/create_formatted_diff'
|
4
|
+
require 'pact_broker/repositories'
|
5
|
+
require 'yaml'
|
8
6
|
|
9
7
|
module PactBroker
|
10
8
|
module Pacts
|
11
9
|
|
12
|
-
class Diff
|
13
|
-
|
10
|
+
class Diff
|
14
11
|
include PactBroker::Repositories
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
next_pact = pact_repository.find_next_pact
|
22
|
-
DiffDecorator.new(pact, previous_distinct_pact, next_pact,
|
12
|
+
|
13
|
+
def process(params)
|
14
|
+
pact = find_pact(params)
|
15
|
+
previous_distinct_pact = pact_repository.find_previous_distinct_pact(pact)
|
16
|
+
|
17
|
+
if previous_distinct_pact
|
18
|
+
next_pact = pact_repository.find_next_pact(previous_distinct_pact)
|
19
|
+
DiffDecorator.new(pact, previous_distinct_pact, next_pact, params[:base_url]).to_text
|
23
20
|
else
|
24
21
|
no_previous_version_message pact
|
25
22
|
end
|
26
23
|
end
|
27
24
|
|
28
|
-
|
29
|
-
|
25
|
+
private
|
26
|
+
|
27
|
+
def find_pact(params)
|
28
|
+
pact_repository.find_pact(params.consumer_name,
|
29
|
+
params.consumer_version_number,
|
30
|
+
params.provider_name)
|
30
31
|
end
|
31
32
|
|
32
|
-
def
|
33
|
-
|
33
|
+
def no_previous_version_message(pact)
|
34
|
+
"No previous distinct version was found for #{pact.name}"
|
34
35
|
end
|
35
36
|
|
36
|
-
private
|
37
37
|
|
38
38
|
# The next pact version after the previous distinct version.
|
39
39
|
# Eg. v1 (previous distinct) -> pactContentA
|
@@ -46,10 +46,7 @@ module PactBroker
|
|
46
46
|
# the latest distinct version content was first created.
|
47
47
|
|
48
48
|
class DiffDecorator
|
49
|
-
|
50
|
-
attr_reader :pact, :previous_distinct_pact, :next_pact, :base_url
|
51
|
-
|
52
|
-
def initialize pact, previous_distinct_pact, next_pact, base_url
|
49
|
+
def initialize(pact, previous_distinct_pact, next_pact, base_url)
|
53
50
|
@pact = pact
|
54
51
|
@previous_distinct_pact = previous_distinct_pact
|
55
52
|
@next_pact = next_pact
|
@@ -62,6 +59,8 @@ module PactBroker
|
|
62
59
|
|
63
60
|
private
|
64
61
|
|
62
|
+
attr_reader :pact, :previous_distinct_pact, :next_pact, :base_url
|
63
|
+
|
65
64
|
def change_date_in_words
|
66
65
|
DateHelper.local_date_in_words next_pact.updated_at
|
67
66
|
end
|
@@ -73,12 +72,13 @@ module PactBroker
|
|
73
72
|
def header
|
74
73
|
title = "# Diff between versions #{previous_distinct_pact.consumer_version_number} and #{pact.consumer_version_number} of the pact between #{pact.consumer.name} and #{pact.provider.name}"
|
75
74
|
description = "The following changes were made #{change_date_ago_in_words} ago (#{change_date_in_words})"
|
75
|
+
|
76
76
|
title + "\n\n" + description
|
77
77
|
end
|
78
78
|
|
79
79
|
def links
|
80
|
-
self_url = PactBroker::Api::PactBrokerUrls.pact_url
|
81
|
-
previous_distinct_url = PactBroker::Api::PactBrokerUrls.pact_url
|
80
|
+
self_url = PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact)
|
81
|
+
previous_distinct_url = PactBroker::Api::PactBrokerUrls.pact_url(base_url, previous_distinct_pact)
|
82
82
|
|
83
83
|
links = {
|
84
84
|
"current-pact-version" => {
|
@@ -103,7 +103,6 @@ module PactBroker
|
|
103
103
|
DateHelper.distance_of_time_in_words next_pact.updated_at, now
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
107
106
|
end
|
108
107
|
end
|
109
108
|
end
|
@@ -20,6 +20,13 @@ module PactBroker
|
|
20
20
|
PactBroker::Domain::Pacticipant.order(:name).all
|
21
21
|
end
|
22
22
|
|
23
|
+
def find_all_pacticipant_versions name
|
24
|
+
PactBroker::Domain::Version
|
25
|
+
.select(:versions__id, :versions__number, :versions__pacticipant_id, :versions__order, :versions__created_at, :versions__updated_at)
|
26
|
+
.join(:pacticipants, {id: :pacticipant_id})
|
27
|
+
.where(name_like(:name, name))
|
28
|
+
end
|
29
|
+
|
23
30
|
def find_by_name_or_create name
|
24
31
|
if pacticipant = find_by_name(name)
|
25
32
|
pacticipant
|
@@ -41,6 +41,10 @@ module PactBroker
|
|
41
41
|
pacticipant_repository.find_by_name(name)
|
42
42
|
end
|
43
43
|
|
44
|
+
def self.find_all_pacticipant_versions name
|
45
|
+
pacticipant_repository.find_all_pacticipant_versions(name)
|
46
|
+
end
|
47
|
+
|
44
48
|
def self.find_pacticipant_repository_url_by_pacticipant_name name
|
45
49
|
pacticipant = pacticipant_repository.find_by_name(name)
|
46
50
|
if pacticipant && pacticipant.repository_url
|
@@ -16,7 +16,7 @@ module PactBroker
|
|
16
16
|
|
17
17
|
def self.errors webhook
|
18
18
|
contract = PactBroker::Api::Contracts::WebhookContract.new(webhook)
|
19
|
-
contract.validate
|
19
|
+
contract.validate(webhook.attributes)
|
20
20
|
contract.errors
|
21
21
|
end
|
22
22
|
|
@@ -71,4 +71,4 @@ module PactBroker
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
74
|
-
end
|
74
|
+
end
|
data/lib/pact_broker/version.rb
CHANGED
data/pact_broker.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# -*- encoding: utf-8 -*-
|
3
2
|
lib = File.expand_path('../lib', __FILE__)
|
4
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
@@ -24,8 +23,9 @@ Gem::Specification.new do |gem|
|
|
24
23
|
#gem.add_runtime_dependency 'pact'
|
25
24
|
gem.add_runtime_dependency 'httparty'
|
26
25
|
gem.add_runtime_dependency 'json'
|
27
|
-
gem.add_runtime_dependency 'roar', '~> 1.
|
28
|
-
gem.add_runtime_dependency 'reform', '~>
|
26
|
+
gem.add_runtime_dependency 'roar', '~> 1.1'
|
27
|
+
gem.add_runtime_dependency 'reform', '~> 2.2.0'
|
28
|
+
gem.add_runtime_dependency 'dry-validation', '~> 0.10.5'
|
29
29
|
gem.add_runtime_dependency 'sequel', '~> 4.23'
|
30
30
|
gem.add_runtime_dependency 'webmachine', '1.4.0'
|
31
31
|
gem.add_runtime_dependency 'versionomy', '~> 0.4'
|
@@ -35,16 +35,14 @@ Gem::Specification.new do |gem|
|
|
35
35
|
gem.add_runtime_dependency 'pact-support', '~>0.4', '>=0.4.2'
|
36
36
|
gem.add_runtime_dependency 'padrino-core', '~>0.12.4'
|
37
37
|
gem.add_runtime_dependency 'haml'
|
38
|
-
gem.add_runtime_dependency 'trailblazer', '~>0.3.0'
|
39
38
|
|
40
39
|
gem.add_development_dependency 'sqlite3'
|
41
40
|
gem.add_development_dependency 'pry'
|
42
41
|
gem.add_development_dependency 'rake', '~>10.0'
|
43
42
|
gem.add_development_dependency 'fakefs', '~>0.4'
|
44
43
|
gem.add_development_dependency 'mysql2', '~>0.3.15'
|
45
|
-
gem.add_development_dependency 'webmock', '~>2.
|
44
|
+
gem.add_development_dependency 'webmock', '~>2.3'
|
46
45
|
gem.add_development_dependency 'rspec', '~>3.0'
|
47
46
|
gem.add_development_dependency 'rspec-its'
|
48
47
|
gem.add_development_dependency 'database_cleaner'
|
49
|
-
|
50
48
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec/support/provider_state_builder'
|
2
|
+
|
3
|
+
describe "Get versions" do
|
4
|
+
|
5
|
+
let(:path) { "/pacticipants/Consumer/versions" }
|
6
|
+
let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
|
7
|
+
|
8
|
+
subject { get path; last_response }
|
9
|
+
|
10
|
+
context "when the pacticipant exists" do
|
11
|
+
|
12
|
+
before do
|
13
|
+
ProviderStateBuilder.new
|
14
|
+
.create_consumer("Consumer")
|
15
|
+
.create_consumer_version("1.0.0")
|
16
|
+
.create_consumer_version("1.0.1")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns a 200 response" do
|
20
|
+
expect(subject.status).to be 200
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns a list of links to the versions" do
|
24
|
+
expect(last_response_body[:_links][:"versions"].size).to eq 2
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when the pacticipant does not exist" do
|
30
|
+
|
31
|
+
it "returns a 404 response" do
|
32
|
+
expect(subject).to be_a_404_response
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|