bbc-a11y 0.0.12 → 0.0.13
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/.ruby-version +1 -0
- data/README.md +9 -11
- data/Rakefile +2 -2
- data/a11y.rb +5 -0
- data/bbc-a11y.gemspec +3 -5
- data/bin/a11y +2 -2
- data/examples/bbc-pages/a11y.rb +2 -6
- data/examples/local-web-app/Gemfile +1 -1
- data/examples/local-web-app/a11y.rb +10 -22
- data/features/check_standards/focusable_controls.feature +62 -0
- data/features/check_standards/form_interactions.feature +45 -0
- data/features/check_standards/form_labels.feature +55 -0
- data/features/check_standards/headings.feature +154 -0
- data/features/check_standards/image_alt.feature +39 -0
- data/features/check_standards/language.feature +46 -0
- data/features/check_standards/main_landmark.feature +39 -0
- data/features/check_standards/tab_index.feature +54 -0
- data/features/cli/display_failing_result.feature +10 -0
- data/features/{exit_status.feature → cli/exit_status.feature} +1 -2
- data/features/cli/provide_muting_tips.feature +25 -0
- data/features/cli/report_configuration_errors.feature +43 -0
- data/features/cli/skipping_standards.feature +15 -0
- data/features/cli/specify_url.feature +9 -0
- data/features/cli/specify_url_via_config.feature +13 -0
- data/features/mute_errors.feature +118 -0
- data/features/step_definitions/steps.rb +25 -1
- data/lib/bbc/a11y/cli.rb +32 -44
- data/lib/bbc/a11y/configuration.rb +56 -22
- data/lib/bbc/a11y/linter.rb +42 -0
- data/lib/bbc/a11y/standards.rb +43 -0
- data/lib/bbc/a11y/standards/anchor_hrefs.rb +18 -0
- data/lib/bbc/a11y/standards/content_follows_headings.rb +22 -0
- data/lib/bbc/a11y/standards/exactly_one_main_heading.rb +20 -0
- data/lib/bbc/a11y/standards/exactly_one_main_landmark.rb +20 -0
- data/lib/bbc/a11y/standards/form_labels.rb +39 -0
- data/lib/bbc/a11y/standards/form_submit_buttons.rb +21 -0
- data/lib/bbc/a11y/standards/heading_hierarchy.rb +34 -0
- data/lib/bbc/a11y/standards/image_alt.rb +18 -0
- data/lib/bbc/a11y/standards/language_attribute.rb +19 -0
- data/lib/bbc/a11y/standards/tab_index.rb +22 -0
- data/lib/bbc/a11y/version +1 -1
- data/spec/bbc/a11y/cli_spec.rb +22 -15
- data/spec/bbc/a11y/configuration_spec.rb +15 -40
- data/standards/support/capybara.rb +1 -2
- metadata +62 -81
- data/features/specify_url_via_cli.feature +0 -10
- data/features/specify_url_via_config.feature +0 -16
- data/lib/bbc/a11y.rb +0 -17
- data/lib/bbc/a11y/cucumber_runner.rb +0 -208
- data/lib/bbc/a11y/cucumber_support.rb +0 -56
- data/lib/bbc/a11y/cucumber_support/disabled_w3c.rb +0 -37
- data/lib/bbc/a11y/cucumber_support/heading_hierarchy.rb +0 -94
- data/lib/bbc/a11y/cucumber_support/language_detector.rb +0 -26
- data/lib/bbc/a11y/cucumber_support/matchers.rb +0 -21
- data/lib/bbc/a11y/cucumber_support/page.rb +0 -94
- data/lib/bbc/a11y/cucumber_support/per_page_checks.rb +0 -28
- data/lib/bbc/a11y/cucumber_support/w3c.rb +0 -36
- data/spec/bbc/a11y/cucumber_support/heading_hierarchy_spec.rb +0 -162
- data/spec/bbc/a11y/cucumber_support/matchers_spec.rb +0 -52
- data/spec/bbc/a11y/cucumber_support/page_spec.rb +0 -197
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10a369a2db0ae8f7e5b16e92a0f57e12ac3343be
|
4
|
+
data.tar.gz: 1b733f1a53afad2c0d200f801ec95ff6ed2ed7c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79571febea89695f33ae26639f47567dec98e73bed577c5ade2559db0b3235db15c3ec6245c5a6878598eda8f5ef163dd67b8c0df61603fb15c3ffe6779bd8db
|
7
|
+
data.tar.gz: de1ff17432e5fe20a0e67572fdbb0b973ff835d86620a12b7f3e63abe28ecb557ec7e7e824c488832c5cad9f19ea45cc962d23e4f084cc5dcc55c48ddff9c1d7
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.3
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[](https://circleci.com/gh/cucumber-ltd/bbc-a11y)
|
2
|
+
|
1
3
|
# WARNING - PROTOTYPE SOFTWARE
|
2
4
|
|
3
5
|
This project is still at an experimental / proof-of-concept stage. Please set your expectations appropriately, but *do* [give us as much feedback](https://github.com/cucumber-ltd/bbc-a11y/issues) as you can.
|
@@ -32,24 +34,20 @@ Now install the gem:
|
|
32
34
|
You'll need to configure a11y with a set of URLs to run the checks against. Create a file `a11y.rb` in the root of your project that looks something like this:
|
33
35
|
|
34
36
|
```
|
35
|
-
|
36
|
-
|
37
|
-
page "http://bbc.co.uk/news"
|
38
|
-
end
|
37
|
+
page "http://bbc.co.uk"
|
38
|
+
page "http://bbc.co.uk/news"
|
39
39
|
```
|
40
40
|
|
41
41
|
### Skipping scenarios
|
42
42
|
|
43
|
-
Nobody's perfect. Use `
|
43
|
+
Nobody's perfect. Use `skip_standard` in the configuration to opt-out of certain checks.
|
44
44
|
|
45
45
|
```
|
46
|
-
|
47
|
-
|
48
|
-
skip_scenario /W3C/
|
49
|
-
end
|
50
|
-
|
51
|
-
page "http://bbc.co.uk/news"
|
46
|
+
page "http://bbc.co.uk" do
|
47
|
+
skip_standard /W3C/
|
52
48
|
end
|
49
|
+
|
50
|
+
page "http://bbc.co.uk/news"
|
53
51
|
```
|
54
52
|
|
55
53
|
A11y will skip any scenarios from the specifications whose name contains that string.
|
data/Rakefile
CHANGED
data/a11y.rb
ADDED
data/bbc-a11y.gemspec
CHANGED
@@ -13,16 +13,14 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.license = "MIT"
|
14
14
|
s.required_ruby_version = ">= 1.9.3"
|
15
15
|
|
16
|
-
s.add_dependency 'cucumber', '~> 2.0.0.rc'
|
17
|
-
s.add_dependency 'rspec', '~> 3.0'
|
18
16
|
s.add_dependency 'capybara'
|
19
|
-
s.add_dependency 'poltergeist'
|
20
|
-
s.add_dependency 'w3c_validators'
|
21
|
-
s.add_dependency 'cld'
|
22
17
|
s.add_dependency 'colorize'
|
18
|
+
|
19
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
23
20
|
s.add_development_dependency 'aruba'
|
24
21
|
s.add_development_dependency 'pry'
|
25
22
|
s.add_development_dependency 'rake'
|
23
|
+
s.add_development_dependency 'cucumber'
|
26
24
|
|
27
25
|
s.rubygems_version = ">= 1.6.1"
|
28
26
|
s.files = `git ls-files`.split("\n").reject {|path| path =~ /\.gitignore$/ }
|
data/bin/a11y
CHANGED
@@ -2,5 +2,5 @@
|
|
2
2
|
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
3
3
|
|
4
4
|
require 'bbc/a11y/cli'
|
5
|
-
|
6
|
-
BBC::A11y::CLI.new($stdin, $stdout, $stderr, ARGV.dup).call
|
5
|
+
|
6
|
+
BBC::A11y::CLI.new($stdin, $stdout, $stderr, ARGV.dup).call
|
data/examples/bbc-pages/a11y.rb
CHANGED
@@ -36,29 +36,17 @@ class Server
|
|
36
36
|
end
|
37
37
|
|
38
38
|
server = Server.new
|
39
|
+
server.start
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
server.start
|
44
|
-
end
|
45
|
-
|
46
|
-
after_all do
|
47
|
-
server.stop
|
48
|
-
end
|
49
|
-
|
50
|
-
page "http://localhost:#{server.port}/perfect.html" do
|
51
|
-
skip_scenario "W3C"
|
52
|
-
end
|
41
|
+
at_exit do
|
42
|
+
server.stop
|
43
|
+
end
|
53
44
|
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
page "http://localhost:#{server.port}/perfect.html" do
|
46
|
+
skip_standard "W3C"
|
47
|
+
end
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
49
|
+
page "http://localhost:#{server.port}/missing_header.html" do
|
50
|
+
skip_standard "W3C"
|
51
|
+
skip_standard "Check headings"
|
64
52
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
Feature: Focusable Controls
|
2
|
+
|
3
|
+
Controls for JavaScript enhanced interactions **must** be `<a>`, `<button>`,
|
4
|
+
or `<input>` elements if that is the only mechanism for controlling them.
|
5
|
+
|
6
|
+
`<a>` elements used for controls **must** have an `href` attribute.
|
7
|
+
|
8
|
+
Controls that have no purpose without JavaScript **must not** be added to the
|
9
|
+
page before the associated code is available capable of running.
|
10
|
+
|
11
|
+
Rationale
|
12
|
+
=========
|
13
|
+
|
14
|
+
When creating controls for user interaction with JavaScript enhanced features,
|
15
|
+
for example a carousel with previous and next controls, the controls must be
|
16
|
+
implemented with elements that provide natively focusable elements with click,
|
17
|
+
keydown, and focus events so they are accessible to keyboard as well as
|
18
|
+
pointing device users. If there is an alternative method of controlling the
|
19
|
+
feature, for example a carousel that automatically displays new content when
|
20
|
+
it receives content then controls that are only available to pointing device
|
21
|
+
users can be used.
|
22
|
+
|
23
|
+
In general, use `<a>` elements when there is a URL associated with the
|
24
|
+
interaction when JavaScript is not enabled, and `<button>` elements for
|
25
|
+
interactions that don't have an associated URL.
|
26
|
+
|
27
|
+
`<a>` elements without a `href` attribute are not keyboard accessible, and
|
28
|
+
therefore must not be used for controls.
|
29
|
+
|
30
|
+
When there is no core (non-JavaScript) interaction then the control must not
|
31
|
+
be added to the document before the associated JavaScript is capable of
|
32
|
+
running as this would lead to controls that apparently do nothing, potentially
|
33
|
+
causing confusion to users.
|
34
|
+
|
35
|
+
Scenario: All anchor tags have href attributes
|
36
|
+
Given a page with the HTML:
|
37
|
+
"""
|
38
|
+
<button type="button">Open panel</button>
|
39
|
+
<ul>
|
40
|
+
<li><a href="/news">News</a></li>
|
41
|
+
<li><a href="#sporttab">Sport</a></li>
|
42
|
+
<li><a href="#entertainmenttab">Entertainment</a></li>
|
43
|
+
</ul>
|
44
|
+
"""
|
45
|
+
When I validate the anchor hrefs standards
|
46
|
+
Then it passes
|
47
|
+
|
48
|
+
Scenario: Some anchor tags do not have href attributes
|
49
|
+
Given a page with the HTML:
|
50
|
+
"""
|
51
|
+
<ul>
|
52
|
+
<li><a>News</a></li>
|
53
|
+
<li><a href="#sport">Sport</a></li>
|
54
|
+
<li><a>Entertainment</a></li>
|
55
|
+
</ul>
|
56
|
+
"""
|
57
|
+
When I validate the anchor hrefs standards
|
58
|
+
Then it fails with the message:
|
59
|
+
"""
|
60
|
+
Anchor has no href attribute: /html/body/ul/li[1]/a
|
61
|
+
Anchor has no href attribute: /html/body/ul/li[3]/a
|
62
|
+
"""
|
@@ -0,0 +1,45 @@
|
|
1
|
+
Feature: Form Interactions
|
2
|
+
|
3
|
+
Forms must have a submit button and forms must not update the location of the
|
4
|
+
page on change, focus, or blur events.
|
5
|
+
|
6
|
+
All `<form>` elements that take user input (i.e. do not consist only of
|
7
|
+
`input[type=hidden]` elements to store state) **must** have a submit button in
|
8
|
+
the form of a `<input>[type=submit,image]` or `<button>[type=submit]` element.
|
9
|
+
|
10
|
+
Changes to the page **must** location must only take place on explicit user
|
11
|
+
action i.e. when a submit button is activated. They must not take place when
|
12
|
+
change (particularly for `select` elements), focus, or blur events are fired.
|
13
|
+
|
14
|
+
Rationale
|
15
|
+
=========
|
16
|
+
|
17
|
+
All forms should have a submit button to provide a clear call to action. This
|
18
|
+
is particularly important to users with cognitive disabilities, but is also
|
19
|
+
beneficial to low vision users as an indication of the end of the form.
|
20
|
+
|
21
|
+
Scenario: Form with a submit button
|
22
|
+
Given a page with the HTML:
|
23
|
+
"""
|
24
|
+
<form action="/search">
|
25
|
+
<label for="q">Search term:</label>
|
26
|
+
<input type="text" name="q" id="q">
|
27
|
+
<input type="submit" value="Search">
|
28
|
+
</form>
|
29
|
+
"""
|
30
|
+
When I validate the form submit buttons standards
|
31
|
+
Then it passes
|
32
|
+
|
33
|
+
Scenario: Form with no submit button
|
34
|
+
Given a page with the HTML:
|
35
|
+
"""
|
36
|
+
<form action="/search">
|
37
|
+
<label for="q">Search term:</label>
|
38
|
+
<input type="text" name="q" id="q">
|
39
|
+
</form>
|
40
|
+
"""
|
41
|
+
When I validate the form submit buttons standards
|
42
|
+
Then it fails with the message:
|
43
|
+
"""
|
44
|
+
Form has no submit button: /html/body/form
|
45
|
+
"""
|
@@ -0,0 +1,55 @@
|
|
1
|
+
Feature: Correctly use form labels
|
2
|
+
|
3
|
+
Form fields that allow input (`select`, and `textarea` elements, and all
|
4
|
+
`input` element types other than image, submit, reset, button, or hidden)
|
5
|
+
**must** have an associated label, either in the form of a `<label>` element
|
6
|
+
or, for simple forms when no visible label is required, a `title` attribute.
|
7
|
+
|
8
|
+
Rationale
|
9
|
+
---------
|
10
|
+
|
11
|
+
Form labels are important for all users in order to understand what the form
|
12
|
+
field is however they are essential for speech output users who cannot easily
|
13
|
+
infer what the form element is by looking at the surrounding content.
|
14
|
+
|
15
|
+
While there are WAI-ARIA attributes that allow for labelling of forms it is
|
16
|
+
not supported in all versions of assistive technologies that BBC users could
|
17
|
+
reasonably expect to be able to use.
|
18
|
+
|
19
|
+
Scenario: All fields have labels or title attributes
|
20
|
+
Given a page with the HTML:
|
21
|
+
"""
|
22
|
+
<label for="search">Search the BBC</label>
|
23
|
+
<input type="text" id="search" name="q" />
|
24
|
+
|
25
|
+
<label for="search2">
|
26
|
+
Search the BBC
|
27
|
+
<input id="search2" type="text" name="q" />
|
28
|
+
</label>
|
29
|
+
|
30
|
+
<input type="text" name="q" title="Search the BBC" />
|
31
|
+
"""
|
32
|
+
When I validate the form labels standards
|
33
|
+
Then it passes
|
34
|
+
|
35
|
+
Scenario: Some fields without labels or title attributes
|
36
|
+
Given a page with the HTML:
|
37
|
+
"""
|
38
|
+
<input type="text" name="name" title="Name" />
|
39
|
+
<input type="email" name="email" title="Email" />
|
40
|
+
|
41
|
+
<textarea name="notes"></textarea>
|
42
|
+
<select name="preference"></select>
|
43
|
+
<input type="text" name="q" value="Search the BBC" />
|
44
|
+
<input type="text" name="q" aria-label="Search the BBC" />
|
45
|
+
<input type="text" name="q" placeholder="Search the BBC" />
|
46
|
+
"""
|
47
|
+
When I validate the form labels standards
|
48
|
+
Then it fails with the message:
|
49
|
+
"""
|
50
|
+
Field has no label or title attribute: /html/body/textarea
|
51
|
+
Field has no label or title attribute: /html/body/select
|
52
|
+
Field has no label or title attribute: /html/body/input[3]
|
53
|
+
Field has no label or title attribute: /html/body/input[4]
|
54
|
+
Field has no label or title attribute: /html/body/input[5]
|
55
|
+
"""
|
@@ -0,0 +1,154 @@
|
|
1
|
+
Feature: Headings
|
2
|
+
|
3
|
+
A document **must** have exactly one `<h1>` element.
|
4
|
+
|
5
|
+
Heading levels after the document `<h1>` element **must** be sequential and **must not** skip heading levels.
|
6
|
+
|
7
|
+
Heading elements **must** be followed by content.
|
8
|
+
|
9
|
+
Rationale
|
10
|
+
=========
|
11
|
+
|
12
|
+
A logical heading structure is invaluable for users of screen readers and similar assistive technologies to help navigate content.
|
13
|
+
|
14
|
+
Users should be able to use the document's `<h1>` identify its main content. Documents should have one main subject.
|
15
|
+
|
16
|
+
Heading levels should not be skipped as a predictable document outline is an important factor for understandability.
|
17
|
+
|
18
|
+
Headings should not be used for non-heading purposes, i.e. to identify blocks of content. A heading should always
|
19
|
+
be followed either by non-heading content or by a heading of one level deeper.
|
20
|
+
|
21
|
+
Scenario: No main heading
|
22
|
+
Given a page with the HTML:
|
23
|
+
"""
|
24
|
+
<h2>Heading 2</h2>
|
25
|
+
"""
|
26
|
+
When I validate the heading standards
|
27
|
+
Then it fails with the message:
|
28
|
+
"""
|
29
|
+
A document must have exactly one heading. Found 0 h1 elements.
|
30
|
+
"""
|
31
|
+
|
32
|
+
Scenario: More than one main heading
|
33
|
+
Given a page with the HTML:
|
34
|
+
"""
|
35
|
+
<h1>Heading 1</h1>
|
36
|
+
<h2>Heading 2</h2>
|
37
|
+
<h1>Heading 1</h1>
|
38
|
+
"""
|
39
|
+
When I validate the heading standards
|
40
|
+
Then it fails with the message:
|
41
|
+
"""
|
42
|
+
A document must have exactly one heading. Found 2 h1 elements:
|
43
|
+
/html/body/h1[1]
|
44
|
+
/html/body/h1[2]
|
45
|
+
"""
|
46
|
+
|
47
|
+
Scenario: Headings in ascending order
|
48
|
+
Given a page with the HTML:
|
49
|
+
"""
|
50
|
+
<h1>Heading 1</h1>
|
51
|
+
<h2>Heading 2</h2>
|
52
|
+
<h3>Heading 3</h3>
|
53
|
+
<h4>Heading 4</h4>
|
54
|
+
<h5>Heading 5</h5>
|
55
|
+
<h6>Heading 6</h6>
|
56
|
+
"""
|
57
|
+
When I validate the heading standards
|
58
|
+
Then it passes
|
59
|
+
|
60
|
+
Scenario: Headings in invalid order
|
61
|
+
Given a page with the HTML:
|
62
|
+
"""
|
63
|
+
<h1>Heading 1</h1>
|
64
|
+
<h3>Heading 3</h3>
|
65
|
+
<h2>Heading 2</h2>
|
66
|
+
"""
|
67
|
+
When I validate the heading standards
|
68
|
+
Then it fails with the message:
|
69
|
+
"""
|
70
|
+
Headings are not in order: h1 is followed by h3
|
71
|
+
"""
|
72
|
+
|
73
|
+
Scenario: Headings jump back up more than one level
|
74
|
+
Given a page with the HTML:
|
75
|
+
"""
|
76
|
+
<h1>Heading 1</h1>
|
77
|
+
<h2>Heading 2</h2>
|
78
|
+
<h3>Heading 3</h3>
|
79
|
+
<h4>Heading 4</h4>
|
80
|
+
<h2>Heading 2b</h2>
|
81
|
+
<h3>Heading 3b</h3>
|
82
|
+
"""
|
83
|
+
When I validate the heading standards
|
84
|
+
Then it passes
|
85
|
+
|
86
|
+
Scenario: Heading is hidden
|
87
|
+
Given a page with the HTML:
|
88
|
+
"""
|
89
|
+
<h1>Heading 1</h1>
|
90
|
+
<h3 style="display:none">Heading 3</h3>
|
91
|
+
<h2>Heading 2</h2>
|
92
|
+
"""
|
93
|
+
When I validate the heading standards
|
94
|
+
Then it fails with the message:
|
95
|
+
"""
|
96
|
+
Headings are not in order: h1 is followed by h3
|
97
|
+
"""
|
98
|
+
|
99
|
+
Scenario: Heading in a script tag
|
100
|
+
Given a page with the HTML:
|
101
|
+
"""
|
102
|
+
<h1>Heading 1</h1>
|
103
|
+
<script>
|
104
|
+
var stuff = "<h3>Heading 3</h3>";
|
105
|
+
</script>
|
106
|
+
<h2>Heading 2</h2>
|
107
|
+
"""
|
108
|
+
When I validate the heading standards
|
109
|
+
Then it passes
|
110
|
+
|
111
|
+
Scenario: Subheading before the first main heading
|
112
|
+
Given a page with the HTML:
|
113
|
+
"""
|
114
|
+
<h3>Ignore me</h3>
|
115
|
+
<h1>Heading 1</h1>
|
116
|
+
<h2>Heading 2</h2>
|
117
|
+
"""
|
118
|
+
When I validate the heading standards
|
119
|
+
Then it passes
|
120
|
+
|
121
|
+
Scenario: Content between headings
|
122
|
+
Given a page with the HTML:
|
123
|
+
"""
|
124
|
+
<div role="main">
|
125
|
+
<h1>Main heading</h1>
|
126
|
+
<p>non-heading content</p>
|
127
|
+
<h2>Another heading</h2>
|
128
|
+
<p>non-heading content</p>
|
129
|
+
<h3>Main content</h3>
|
130
|
+
<h2>Secondary content</h2>
|
131
|
+
<p>non-heading content</p>
|
132
|
+
<h2>Tertiary content</h2>
|
133
|
+
<p>Lorem ipsum…</p>
|
134
|
+
</div>
|
135
|
+
"""
|
136
|
+
When I validate the heading standards
|
137
|
+
Then it passes
|
138
|
+
|
139
|
+
Scenario: No content between headings
|
140
|
+
Given a page with the HTML:
|
141
|
+
"""
|
142
|
+
<div role="main">
|
143
|
+
<h1>Main heading</h1>
|
144
|
+
<p>non-heading content</p>
|
145
|
+
<h2>Secondary content</h2>
|
146
|
+
<h2>Tertiary content</h2>
|
147
|
+
<p>non-heading content</p>
|
148
|
+
</div>
|
149
|
+
"""
|
150
|
+
When I validate the heading standards
|
151
|
+
Then it fails with the message:
|
152
|
+
"""
|
153
|
+
Heading elements must be followed by content. No content follows a h2.
|
154
|
+
"""
|