datatrue_client 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/LICENSE.txt +1 -1
- data/README.md +99 -86
- data/exe/datatrue_client +5 -22
- data/lib/datatrue_client/test_run.rb +47 -0
- data/lib/datatrue_client/version.rb +1 -1
- metadata +23 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e313cd838909047b0f150bea93e2a2af4c0349eeac86c23dd28c476ef0d7e3c9
|
4
|
+
data.tar.gz: e45b0fe798c67621b77d7ba28674817d671ab844880353d15d7f287d3354f671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a746a8dc707b255ba318d37fe869368282e200b5d0c3695ce652ab9f8b4811411b0a9a0442a718c00003d11e9749856445ec8db4eab66898d4b220819a56210d
|
7
|
+
data.tar.gz: 9c73891d5c13bb9c56285a53faaece218dad4b5d1b2569fdd7a64b7218add9202ff344f0681deff0fe83038322745630032d05136b121ba5ca6fb0bd881f73f3
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.5
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,19 @@ DataTrue is a SaaS platform to audit, monitor and validate tags, dataLayers and
|
|
4
4
|
|
5
5
|
This ruby client allows you to trigger DataTrue tests from a Continuous Integration tool such as [Jenkins](https://jenkins.io/), [Teamcity](https://www.jetbrains.com/teamcity/), [Travis CI](https://travis-ci.org/), [Codeship](https://codeship.com/) and others. If you’re practicing Continuous Delivery, it can be used to trigger a test of your application as soon as changes are released.
|
6
6
|
|
7
|
+
## Table of Contents
|
8
|
+
|
9
|
+
- [DataTrue API client](#datatrue-api-client)
|
10
|
+
- [Table of Contents](#table-of-contents)
|
11
|
+
- [Usage](#usage)
|
12
|
+
- [Command-line usage](#command-line-usage)
|
13
|
+
- [Environment variables](#environment-variables)
|
14
|
+
- [Usage in a Ruby application](#usage-in-a-ruby-application)
|
15
|
+
- [Support](#support)
|
16
|
+
- [Contributing](#contributing)
|
17
|
+
- [Development](#development)
|
18
|
+
- [License](#license)
|
19
|
+
|
7
20
|
## Usage
|
8
21
|
|
9
22
|
You will need a DataTrue account ([free sign-up](https://datatrue.com/?utm_source=github&utm_medium=listing&utm_campaign=API_Client)) to use this gem. To get your API key go to the [Accounts page](https://datatrue.com/accounts/?utm_source=github&utm_medium=listing&utm_campaign=API_Client), select your account and click on "Generate API Key".
|
@@ -12,7 +25,9 @@ The next steps assume you have a test suite created in DataTrue. Read our [Know
|
|
12
25
|
|
13
26
|
Install the gem on the system you want to trigger your tests from:
|
14
27
|
|
15
|
-
|
28
|
+
```bash
|
29
|
+
$ gem install datatrue_client
|
30
|
+
```
|
16
31
|
|
17
32
|
Alternatively, if you want to include the client as part of your ruby application, you can add this line to your Gemfile:
|
18
33
|
|
@@ -22,10 +37,10 @@ gem 'datatrue_client', :group => [:test, :development]
|
|
22
37
|
|
23
38
|
### Command-line usage
|
24
39
|
|
25
|
-
Use the
|
40
|
+
Use the following CLI syntax to select your test(s) or test suite along with other options.
|
26
41
|
|
27
|
-
```
|
28
|
-
datatrue_client run 1539 -a rtTlaqucG9RrTg1G2L1O0u -t suite \
|
42
|
+
```bash
|
43
|
+
$ datatrue_client run 1539 -a rtTlaqucG9RrTg1G2L1O0u -t suite \
|
29
44
|
-v HOSTNAME=datatrue.com,GTMID=GTM-ABCXYZ \
|
30
45
|
-e 543,544
|
31
46
|
|
@@ -38,11 +53,12 @@ datatrue_client: test_run_id=52454 finished result=passed.
|
|
38
53
|
```
|
39
54
|
|
40
55
|
The exit status of the application will change according to test results:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
56
|
+
|
57
|
+
- `0`: test run successful, result=passed.
|
58
|
+
- `1`: test run successful, result=failed.
|
59
|
+
- `-1`: generic test run error. See output detail.
|
60
|
+
- `-2`: authentication or authorisation error. Check your API key and test identifiers.
|
61
|
+
- `-3`: quota exceeded. You have used-up all your subscription allowance for this period.
|
46
62
|
|
47
63
|
If you want to ignore the exit status, use the shell's `||` operator; e.g.: `datatrue_client [options] || true`. This will ensure that the exit status is always `0`.
|
48
64
|
|
@@ -50,15 +66,15 @@ If you want to ignore the exit status, use the shell's `||` operator; e.g.: `dat
|
|
50
66
|
|
51
67
|
_Commands_:
|
52
68
|
|
53
|
-
|
69
|
+
- `run`: triggers a new run of tests or a test suite and waits for it to finish.
|
54
70
|
|
55
71
|
```text
|
56
72
|
datatrue_client run <suite_id | test_id_1,test_id_2,...> -a <api_key>
|
57
73
|
[-t | --type=suite|test] [-v | --variables foo=bar,thunder=flash]
|
58
|
-
[-e | --email-users '1,2,3...'] [-
|
74
|
+
[-e | --email-users '1,2,3...'] [-s | --silent]
|
59
75
|
```
|
60
76
|
|
61
|
-
|
77
|
+
- `trigger`: triggers a new run of tests or a test suite and exits immediately.
|
62
78
|
|
63
79
|
```text
|
64
80
|
datatrue_client trigger <suite_id | test_id_1,test_id_2,...> -a <api_key>
|
@@ -68,93 +84,92 @@ datatrue_client trigger <suite_id | test_id_1,test_id_2,...> -a <api_key>
|
|
68
84
|
|
69
85
|
_Options_:
|
70
86
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
87
|
+
- `-a` or `--api-key`: The DataTrue API key. Overrides the API key provided as an environment variable.
|
88
|
+
- `-t` or `--type`: The type of test to be run. Valid options are `test` or `suite`.
|
89
|
+
- `-v` or `--variables`: Variables provided to the test. These can be used to change behaviour of your test, provide credentials and more.
|
90
|
+
- `-e` or `--email-users`: Comma-separated list of user identifiers who will receive an email with the test results.
|
91
|
+
- `-s` or `--silent`: Suppress all application output.
|
92
|
+
- `-h` or `--help`: Show help message.
|
93
|
+
|
94
|
+
_Specific options for run_:
|
95
|
+
|
96
|
+
- `--timeout`: Time to wait before the run finishes.
|
77
97
|
|
78
98
|
#### Environment variables
|
79
99
|
|
80
|
-
|
100
|
+
- `DATATRUE_API_KEY`: your DataTrue API key. The `-a` option takes precedence.
|
81
101
|
|
82
102
|
### Usage in a Ruby application
|
83
103
|
|
84
104
|
Trigger a test run:
|
85
105
|
|
86
|
-
```
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
106
|
+
```ruby
|
107
|
+
test_run = DatatrueClient::TestRun.new({
|
108
|
+
host: 'localhost:3000',
|
109
|
+
scheme: 'http',
|
110
|
+
api_key: '_AHQZRHZ3kD0kpa0Al-SJg', # please remember to generate your own key on datatrue.com
|
111
|
+
|
112
|
+
test_run: {
|
113
|
+
test_class: 'TestScenario',
|
114
|
+
test_id: 1
|
115
|
+
},
|
116
|
+
variables: {
|
117
|
+
key: value
|
118
|
+
},
|
119
|
+
|
120
|
+
polling_interval: 2, # in seconds, 2 by default
|
121
|
+
polling_timeout: 120 # in seconds, 60 by default
|
122
|
+
})
|
103
123
|
```
|
104
124
|
|
105
125
|
Query progress:
|
106
126
|
|
107
|
-
```
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
127
|
+
```ruby
|
128
|
+
test_run.query_progress
|
129
|
+
|
130
|
+
# returns the progress hash
|
131
|
+
#
|
132
|
+
# {
|
133
|
+
# time: 1463359905,
|
134
|
+
# status: "running",
|
135
|
+
# uuid: "a1f7868b1db44d38c16585ce37e4ac3f",
|
136
|
+
# num: 4,
|
137
|
+
# total: 5,
|
138
|
+
# progress: {
|
139
|
+
# percentage: 80,
|
140
|
+
# steps_total: 4,
|
141
|
+
# tests: [
|
142
|
+
# {
|
143
|
+
# id: 1,
|
144
|
+
# name: "Test name",
|
145
|
+
# state: "running",
|
146
|
+
# actions_completed: 4,
|
147
|
+
# actions_total: 5,
|
148
|
+
# steps: [
|
149
|
+
# {
|
150
|
+
# name: "Step name",
|
151
|
+
# running: false,
|
152
|
+
# pending: false,
|
153
|
+
# error: nil,
|
154
|
+
# tags: [
|
155
|
+
# { name: "Tag name', enabled: true, valid: true },
|
156
|
+
# ...
|
157
|
+
# ]
|
158
|
+
# },
|
159
|
+
# ...
|
160
|
+
# ]
|
161
|
+
# },
|
162
|
+
# ...
|
163
|
+
# ]
|
164
|
+
# }
|
165
|
+
# }
|
144
166
|
```
|
145
167
|
|
146
168
|
Poll progress (blocks until the run is finished or timed out):
|
147
169
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
The DataTrue client can output test results in the [JUnit format](https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd) which can then be parsed by the [Jenkins JUnit plugin](https://wiki.jenkins-ci.org/display/JENKINS/JUnit+Plugin) and incorporated into your test results.
|
153
|
-
|
154
|
-
Here's an example of what the results look like in Jenkins v1.6.
|
155
|
-
|
156
|
-
<img src="documentation/jenkins_datatrue_test_result_summary.png?raw=true" alt="DataTrue test result summary in Jenkins" height="400"/>
|
157
|
-
|
170
|
+
```ruby
|
171
|
+
test_run.poll_progress
|
172
|
+
```
|
158
173
|
|
159
174
|
## Support
|
160
175
|
|
@@ -164,8 +179,7 @@ If you believe you have found a bug, please [reach-out using the support website
|
|
164
179
|
|
165
180
|
## Contributing
|
166
181
|
|
167
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
168
|
-
|
182
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/datatrue-analytics/datatrue-api-client>.
|
169
183
|
|
170
184
|
### Development
|
171
185
|
|
@@ -173,7 +187,6 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
173
187
|
|
174
188
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
175
189
|
|
176
|
-
|
177
190
|
## License
|
178
191
|
|
179
192
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/exe/datatrue_client
CHANGED
@@ -93,18 +93,6 @@ def datatrue_print(message)
|
|
93
93
|
puts "datatrue_client: #{message}"
|
94
94
|
end
|
95
95
|
|
96
|
-
def process_result(details)
|
97
|
-
if details[:status] == 'completed'
|
98
|
-
if details[:progress]['tests'].all? { |result| ['success', 'validated'].include? result['state'] }
|
99
|
-
status = 'passed'
|
100
|
-
else
|
101
|
-
status = 'failed'
|
102
|
-
end
|
103
|
-
else
|
104
|
-
status = details[:status]
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
96
|
begin
|
109
97
|
options = parse(ARGV)
|
110
98
|
command = ARGV.shift
|
@@ -124,15 +112,6 @@ begin
|
|
124
112
|
exit
|
125
113
|
end
|
126
114
|
|
127
|
-
datatrue_print_progress = Proc.new do |progress, details|
|
128
|
-
datatrue_print %{
|
129
|
-
test_run_id=#{details[:options]['test_run_id']}
|
130
|
-
step=#{details[:num]}
|
131
|
-
total_steps=#{details[:total]}
|
132
|
-
result=#{process_result(details)}
|
133
|
-
}.gsub(/\s+/, ' ').strip
|
134
|
-
end
|
135
|
-
|
136
115
|
test_run = DatatrueClient::TestRun.new({
|
137
116
|
host: options.host,
|
138
117
|
scheme: options.scheme,
|
@@ -150,8 +129,12 @@ begin
|
|
150
129
|
datatrue_print "job=#{test_run.job_id} created for test=\"#{test_run.title}\"" unless options.silent
|
151
130
|
|
152
131
|
if command == 'run'
|
132
|
+
datatrue_print_progress = Proc.new do |progress, details|
|
133
|
+
datatrue_print(DatatrueClient::TestRun.build_progress_message(details))
|
134
|
+
end
|
135
|
+
|
153
136
|
res = test_run.poll_progress(options.silent ? nil : datatrue_print_progress)
|
154
|
-
|
137
|
+
DatatrueClient::TestRun.get_progress_status(res) == 'passed' ? exit : exit(1)
|
155
138
|
else
|
156
139
|
exit
|
157
140
|
end
|
@@ -5,6 +5,53 @@ module DatatrueClient
|
|
5
5
|
class QuotaExceeded < StandardError; end
|
6
6
|
|
7
7
|
class TestRun
|
8
|
+
class << self
|
9
|
+
# @param details [Hash] The progress details hash. See CI API doc for the shape.
|
10
|
+
# @return [String]
|
11
|
+
def get_progress_status(details)
|
12
|
+
if details[:status] == 'completed'
|
13
|
+
if details[:progress]['tests'].all? { |result| ['success', 'validated'].include? result['state'] }
|
14
|
+
status = 'passed'
|
15
|
+
else
|
16
|
+
status = 'failed'
|
17
|
+
end
|
18
|
+
else
|
19
|
+
status = details[:status]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param details [Hash] The progress details hash. See CI API doc for the shape.
|
24
|
+
# @return [String]
|
25
|
+
def build_progress_message(details)
|
26
|
+
status = get_progress_status(details)
|
27
|
+
tests = details.dig(:progress, 'tests') || []
|
28
|
+
steps = tests.map { |test| test['steps'] }.compact.flatten
|
29
|
+
total_steps = details.dig(:progress, 'steps_total')
|
30
|
+
current_step_index = steps.index { |step| step['running'] }
|
31
|
+
|
32
|
+
if current_step_index
|
33
|
+
# read step and crawled pages details
|
34
|
+
step = steps[current_step_index]
|
35
|
+
is_coverage_step = step['actions_total'] > 1
|
36
|
+
coverage_step_details = " (#{step['actions_completed']}/#{step['actions_total']} pages)"
|
37
|
+
|
38
|
+
message = %{
|
39
|
+
test_run_id=#{details[:options]['test_run_id']}
|
40
|
+
step=#{current_step_index + 1}#{is_coverage_step ? coverage_step_details : ''}
|
41
|
+
total_steps=#{total_steps}
|
42
|
+
result=#{status}
|
43
|
+
}
|
44
|
+
else
|
45
|
+
message = %{
|
46
|
+
test_run_id=#{details[:options]['test_run_id']}
|
47
|
+
result=#{status}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
message.gsub(/\s+/, ' ').strip
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
8
55
|
attr_reader :job_id, :title, :progress
|
9
56
|
attr_accessor :polling_timeout, :polling_interval
|
10
57
|
|
metadata
CHANGED
@@ -1,103 +1,103 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datatrue_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ziyu Wang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.11'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.11'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '10.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '3.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: webmock
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '2.0'
|
62
|
-
- -
|
62
|
+
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: 2.0.1
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- - ~>
|
69
|
+
- - "~>"
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '2.0'
|
72
|
-
- -
|
72
|
+
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 2.0.1
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: addressable
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
|
-
- - ~>
|
79
|
+
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: 2.4.0
|
82
82
|
type: :runtime
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- - ~>
|
86
|
+
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: 2.4.0
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: rest-client
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
|
-
- - ~>
|
93
|
+
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: 2.0.2
|
96
96
|
type: :runtime
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
|
-
- - ~>
|
100
|
+
- - "~>"
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: 2.0.2
|
103
103
|
description: This ruby client allows you to trigger DataTrue tests from a Continuous
|
@@ -111,9 +111,10 @@ executables:
|
|
111
111
|
extensions: []
|
112
112
|
extra_rdoc_files: []
|
113
113
|
files:
|
114
|
-
- .gitignore
|
115
|
-
- .rspec
|
116
|
-
- .
|
114
|
+
- ".gitignore"
|
115
|
+
- ".rspec"
|
116
|
+
- ".ruby-version"
|
117
|
+
- ".travis.yml"
|
117
118
|
- Gemfile
|
118
119
|
- LICENSE.txt
|
119
120
|
- README.md
|
@@ -137,17 +138,17 @@ require_paths:
|
|
137
138
|
- lib
|
138
139
|
required_ruby_version: !ruby/object:Gem::Requirement
|
139
140
|
requirements:
|
140
|
-
- -
|
141
|
+
- - ">="
|
141
142
|
- !ruby/object:Gem::Version
|
142
143
|
version: '0'
|
143
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
145
|
requirements:
|
145
|
-
- -
|
146
|
+
- - ">="
|
146
147
|
- !ruby/object:Gem::Version
|
147
148
|
version: '0'
|
148
149
|
requirements: []
|
149
150
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.
|
151
|
+
rubygems_version: 2.7.6.2
|
151
152
|
signing_key:
|
152
153
|
specification_version: 4
|
153
154
|
summary: Ruby wrapper for DataTrue REST API.
|