eaa-kit 0.1.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.
@@ -0,0 +1,168 @@
1
+ import axe from "axe-core";
2
+ //#region src/audit/result.ts
3
+ /** WCAG 2.2 AA and everything it builds on. Best-practice rules stay off. */
4
+ const DEFAULT_TAGS = [
5
+ "wcag2a",
6
+ "wcag2aa",
7
+ "wcag21a",
8
+ "wcag21aa",
9
+ "wcag22aa"
10
+ ];
11
+ function runOptions(tags) {
12
+ return {
13
+ runOnly: {
14
+ type: "tag",
15
+ values: [...tags]
16
+ },
17
+ resultTypes: ["violations", "incomplete"],
18
+ preload: false
19
+ };
20
+ }
21
+ /**
22
+ * Turn raw axe-core output into a PageAudit, shared by both engines so their
23
+ * reports are directly comparable.
24
+ *
25
+ * The `blind` map is what differs: jsdom passes the rules it cannot evaluate,
26
+ * a real browser passes an empty map and keeps every verdict axe-core reached.
27
+ */
28
+ function shapeResults(results, options) {
29
+ const { blind } = options;
30
+ const violations = [];
31
+ const incomplete = [];
32
+ const passes = [];
33
+ const inapplicable = [];
34
+ const claimed = /* @__PURE__ */ new Set();
35
+ for (const result of results.violations) {
36
+ if (claimed.has(result.id)) continue;
37
+ claimed.add(result.id);
38
+ const rule = blind.get(result.id);
39
+ if (rule) incomplete.push(toIncomplete(result, "engine-limitation", rule.detail));
40
+ else violations.push(toFinding(result));
41
+ }
42
+ for (const result of results.incomplete) {
43
+ if (claimed.has(result.id)) continue;
44
+ claimed.add(result.id);
45
+ const rule = blind.get(result.id);
46
+ incomplete.push(rule ? toIncomplete(result, "engine-limitation", rule.detail) : toIncomplete(result, "needs-review", result.description));
47
+ }
48
+ for (const result of results.passes) {
49
+ if (claimed.has(result.id)) continue;
50
+ claimed.add(result.id);
51
+ const rule = blind.get(result.id);
52
+ if (rule) incomplete.push(toIncomplete(result, "engine-limitation", rule.detail));
53
+ else passes.push(toOutcome(result));
54
+ }
55
+ for (const result of results.inapplicable) {
56
+ if (claimed.has(result.id)) continue;
57
+ claimed.add(result.id);
58
+ const rule = blind.get(result.id);
59
+ if (rule?.applicabilityUnreliable) incomplete.push(toIncomplete(result, "engine-limitation", rule.detail));
60
+ else inapplicable.push(toOutcome(result));
61
+ }
62
+ for (const [ruleId, rule] of blind) {
63
+ if (claimed.has(ruleId)) continue;
64
+ const metadata = ruleMetadata(ruleId);
65
+ if (!metadata) continue;
66
+ incomplete.push({
67
+ ruleId,
68
+ impact: null,
69
+ help: metadata.help,
70
+ helpUrl: metadata.helpUrl,
71
+ successCriteria: successCriteria(metadata.tags),
72
+ enClauses: enClauses(metadata.tags),
73
+ tags: metadata.tags,
74
+ nodes: [],
75
+ reason: "engine-limitation",
76
+ reasonDetail: rule.detail
77
+ });
78
+ }
79
+ return {
80
+ relativePath: options.relativePath,
81
+ absolutePath: options.absolutePath,
82
+ url: options.url,
83
+ engine: options.engine,
84
+ violations,
85
+ incomplete: incomplete.sort(byRuleId),
86
+ passes: passes.sort(byRuleId),
87
+ inapplicable: inapplicable.sort(byRuleId),
88
+ durationMs: options.durationMs
89
+ };
90
+ }
91
+ /** A page that could not be audited: no verdicts, and the reason recorded. */
92
+ function failedPage(options, error) {
93
+ return {
94
+ relativePath: options.relativePath,
95
+ absolutePath: options.absolutePath,
96
+ url: options.url,
97
+ engine: options.engine,
98
+ violations: [],
99
+ incomplete: [],
100
+ passes: [],
101
+ inapplicable: [],
102
+ durationMs: options.durationMs,
103
+ error
104
+ };
105
+ }
106
+ function byRuleId(a, b) {
107
+ return a.ruleId.localeCompare(b.ruleId);
108
+ }
109
+ function toOutcome(result) {
110
+ return {
111
+ ruleId: result.id,
112
+ help: result.help,
113
+ helpUrl: result.helpUrl,
114
+ successCriteria: successCriteria(result.tags),
115
+ enClauses: enClauses(result.tags),
116
+ tags: result.tags
117
+ };
118
+ }
119
+ function toFinding(result) {
120
+ return {
121
+ ...toOutcome(result),
122
+ impact: result.impact ?? null,
123
+ nodes: result.nodes.map(toFindingNode)
124
+ };
125
+ }
126
+ function toIncomplete(result, reason, detail) {
127
+ return {
128
+ ...toFinding(result),
129
+ reason,
130
+ reasonDetail: detail
131
+ };
132
+ }
133
+ function toFindingNode(node) {
134
+ return {
135
+ html: node.html,
136
+ target: node.target.map((selector) => String(selector)),
137
+ ...node.failureSummary ? { failureSummary: node.failureSummary } : {}
138
+ };
139
+ }
140
+ function ruleMetadata(ruleId) {
141
+ const rule = axe.getRules().find((candidate) => candidate.ruleId === ruleId);
142
+ if (!rule) return void 0;
143
+ return {
144
+ help: rule.description,
145
+ helpUrl: rule.helpUrl,
146
+ tags: rule.tags
147
+ };
148
+ }
149
+ /** `wcag143` -> `1.4.3`, `wcag258` -> `2.5.8`, `wcag2411` -> `2.4.11`. */
150
+ function successCriteria(tags) {
151
+ const criteria = /* @__PURE__ */ new Set();
152
+ for (const tag of tags) {
153
+ const match = /^wcag(\d)(\d)(\d{1,2})$/.exec(tag);
154
+ if (match?.[1] && match[2] && match[3]) criteria.add(`${match[1]}.${match[2]}.${match[3]}`);
155
+ }
156
+ return [...criteria].sort();
157
+ }
158
+ /** `EN-9.1.4.3` -> `9.1.4.3`. */
159
+ function enClauses(tags) {
160
+ const clauses = /* @__PURE__ */ new Set();
161
+ for (const tag of tags) {
162
+ const match = /^EN-(\d+(?:\.\d+)+)$/.exec(tag);
163
+ if (match?.[1]) clauses.add(match[1]);
164
+ }
165
+ return [...clauses].sort();
166
+ }
167
+ //#endregion
168
+ export { shapeResults as i, failedPage as n, runOptions as r, DEFAULT_TAGS as t };
@@ -0,0 +1,192 @@
1
+ import { i as isImpactLevel } from "./impact-DvgBjupx.js";
2
+ import { t as TOOL_VERSION } from "./version-B3v4rNoG.js";
3
+ import { t as elementFingerprint } from "./fingerprint-DRoneAjj.js";
4
+ import path from "node:path";
5
+ //#region src/audit/report/sarif.ts
6
+ const SARIF_VERSION = "2.1.0";
7
+ const SARIF_SCHEMA = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json";
8
+ /**
9
+ * Map axe-core's impact onto SARIF's level.
10
+ *
11
+ * An unclassified impact becomes `error` rather than something quieter: a
12
+ * missing impact is a gap in what we know, and the rest of the tool already
13
+ * refuses to wave those through (see meetsThreshold).
14
+ */
15
+ function toSarifLevel(impact) {
16
+ if (impact === null || !isImpactLevel(impact)) return "error";
17
+ switch (impact) {
18
+ case "critical":
19
+ case "serious": return "error";
20
+ case "moderate": return "warning";
21
+ case "minor": return "note";
22
+ }
23
+ }
24
+ /**
25
+ * SARIF 2.1.0 log for GitHub code scanning.
26
+ *
27
+ * Only violations become results. incomplete findings are deliberately left
28
+ * out: "a human must look at this" and "this engine is blind here" are not
29
+ * defects at a source location, and filing thousands of them as alerts would
30
+ * bury the failures that are real. The counts are kept in `run.properties` so
31
+ * the information survives in the artifact, and the JSON format carries them in
32
+ * full.
33
+ */
34
+ function buildSarifReport(audits, options) {
35
+ const rules = buildRules(audits);
36
+ const ruleIndex = new Map(rules.map((rule, index) => [rule.id, index]));
37
+ const cwd = options.cwd ?? process.cwd();
38
+ const results = [];
39
+ const notifications = [];
40
+ for (const audit of audits) {
41
+ const uri = artifactUri(options.directory, audit.relativePath, cwd);
42
+ if (audit.error) {
43
+ notifications.push({
44
+ level: "error",
45
+ message: { text: `Page could not be audited: ${audit.error}` },
46
+ locations: [{ physicalLocation: { artifactLocation: { uri } } }]
47
+ });
48
+ continue;
49
+ }
50
+ for (const finding of audit.violations) {
51
+ const index = ruleIndex.get(finding.ruleId);
52
+ if (index === void 0) continue;
53
+ results.push(...toResults(finding, index, uri));
54
+ }
55
+ for (const finding of audit.accepted ?? []) {
56
+ const index = ruleIndex.get(finding.ruleId);
57
+ if (index === void 0) continue;
58
+ results.push(...toResults(finding, index, uri, SUPPRESSED));
59
+ }
60
+ }
61
+ return {
62
+ $schema: SARIF_SCHEMA,
63
+ version: SARIF_VERSION,
64
+ runs: [{
65
+ tool: { driver: {
66
+ name: "eaa-kit",
67
+ version: TOOL_VERSION,
68
+ rules
69
+ } },
70
+ invocations: [{
71
+ executionSuccessful: notifications.length === 0,
72
+ endTimeUtc: (options.now ?? /* @__PURE__ */ new Date()).toISOString(),
73
+ toolExecutionNotifications: notifications
74
+ }],
75
+ results,
76
+ properties: summaryProperties(audits)
77
+ }]
78
+ };
79
+ }
80
+ function serialiseSarifReport(log) {
81
+ return `${JSON.stringify(log, null, 2)}\n`;
82
+ }
83
+ /**
84
+ * One result per offending element, not per rule: a SARIF result carries a
85
+ * single primary location, and one alert per element is what a reviewer acts
86
+ * on. A violation that reported no elements still gets one result on the page.
87
+ */
88
+ const SUPPRESSED = [{
89
+ kind: "external",
90
+ justification: "Recorded in the eaa-kit baseline"
91
+ }];
92
+ function toResults(finding, ruleIndex, uri, suppressions) {
93
+ const level = toSarifLevel(finding.impact);
94
+ const location = { physicalLocation: { artifactLocation: { uri } } };
95
+ if (finding.nodes.length === 0) return [{
96
+ ruleId: finding.ruleId,
97
+ ruleIndex,
98
+ level,
99
+ kind: "fail",
100
+ message: { text: finding.help },
101
+ locations: [location],
102
+ partialFingerprints: fingerprint(finding.ruleId, "", ""),
103
+ ...suppressions ? { suppressions } : {}
104
+ }];
105
+ return finding.nodes.map((node) => {
106
+ const selector = node.target.join(" ");
107
+ return {
108
+ ruleId: finding.ruleId,
109
+ ruleIndex,
110
+ level,
111
+ kind: "fail",
112
+ message: { text: `${finding.help}. Element: ${selector}` },
113
+ locations: [location],
114
+ partialFingerprints: fingerprint(finding.ruleId, selector, node.html),
115
+ ...suppressions ? { suppressions } : {}
116
+ };
117
+ });
118
+ }
119
+ /**
120
+ * Identifies an alert across runs. Deliberately excludes the file path, so that
121
+ * moving a page does not close one alert and open an identical one; GitHub
122
+ * combines the fingerprint with the location itself.
123
+ */
124
+ function fingerprint(ruleId, selector, html) {
125
+ return { "eaaKit/v1": elementFingerprint(ruleId, selector, html) };
126
+ }
127
+ /** Every rule the run knows about, so the catalogue is complete in GitHub. */
128
+ function buildRules(audits) {
129
+ const rules = /* @__PURE__ */ new Map();
130
+ for (const audit of audits) {
131
+ const outcomes = [
132
+ ...audit.violations,
133
+ ...audit.accepted ?? [],
134
+ ...audit.incomplete,
135
+ ...audit.passes,
136
+ ...audit.inapplicable
137
+ ];
138
+ for (const outcome of outcomes) {
139
+ if (rules.has(outcome.ruleId)) continue;
140
+ rules.set(outcome.ruleId, toSarifRule(outcome));
141
+ }
142
+ }
143
+ return [...rules.values()].sort((a, b) => a.id.localeCompare(b.id));
144
+ }
145
+ function toSarifRule(outcome) {
146
+ const criteria = outcome.successCriteria.map((criterion) => `WCAG ${criterion}`);
147
+ const clauses = outcome.enClauses.map((clause) => `EN 301 549 ${clause}`);
148
+ const references = [...criteria, ...clauses].join(", ");
149
+ return {
150
+ id: outcome.ruleId,
151
+ shortDescription: { text: outcome.help },
152
+ ...outcome.helpUrl ? { helpUri: outcome.helpUrl } : {},
153
+ help: { text: references ? `${outcome.help}\n\n${references}` : outcome.help },
154
+ properties: { tags: [
155
+ "accessibility",
156
+ ...outcome.successCriteria.map((criterion) => `wcag-${criterion}`),
157
+ ...outcome.enClauses.map((clause) => `en-301-549-${clause}`)
158
+ ] }
159
+ };
160
+ }
161
+ /**
162
+ * Coverage that has no place in `results` but should not vanish: a SARIF log
163
+ * with no results must not be mistaken for "everything was checked".
164
+ */
165
+ function summaryProperties(audits) {
166
+ let needsReview = 0;
167
+ let notEvaluated = 0;
168
+ const notEvaluatedRules = /* @__PURE__ */ new Set();
169
+ for (const audit of audits) for (const finding of audit.incomplete) if (finding.reason === "engine-limitation") {
170
+ notEvaluated += 1;
171
+ notEvaluatedRules.add(finding.ruleId);
172
+ } else needsReview += 1;
173
+ return {
174
+ engine: audits[0]?.engine ?? "jsdom",
175
+ pages: audits.length,
176
+ needsReview,
177
+ notEvaluated,
178
+ notEvaluatedRules: [...notEvaluatedRules].sort()
179
+ };
180
+ }
181
+ /**
182
+ * Artifact URIs are relative to the working directory and POSIX-separated, so
183
+ * GitHub can line them up with files in the repository.
184
+ */
185
+ function artifactUri(directory, relativePath, cwd) {
186
+ const absolute = path.resolve(cwd, directory, relativePath);
187
+ const relative = path.relative(cwd, absolute);
188
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return relativePath;
189
+ return relative.split(path.sep).join("/");
190
+ }
191
+ //#endregion
192
+ export { buildSarifReport, serialiseSarifReport };
@@ -0,0 +1,127 @@
1
+ # Erklärung zur Barrierefreiheit
2
+
3
+ {{ provider.legalName }} ist bemüht, die Website {{ site.name }} im Einklang mit dem
4
+ österreichischen Barrierefreiheitsgesetz (BaFG) barrierefrei zugänglich zu machen. Das
5
+ BaFG setzt die Richtlinie (EU) 2019/882 (European Accessibility Act) in österreichisches
6
+ Recht um.
7
+
8
+ Diese Erklärung zur Barrierefreiheit gilt für {{ site.url }}.
9
+
10
+ ## Stand der Vereinbarkeit mit den Anforderungen
11
+
12
+ {{#if compliance.isCompliant}}
13
+ Diese Website ist mit {{ compliance.standard }} vollständig vereinbar.
14
+ {{/if}}
15
+ {{#if compliance.isPartiallyCompliant}}
16
+ Diese Website ist mit {{ compliance.standard }} teilweise vereinbar. Die im folgenden
17
+ Abschnitt aufgeführten Inhalte sind aus den jeweils genannten Gründen nicht barrierefrei.
18
+ {{/if}}
19
+ {{#if compliance.isNonCompliant}}
20
+ Diese Website ist mit {{ compliance.standard }} nicht vereinbar. Die im folgenden Abschnitt
21
+ aufgeführten Inhalte sind aus den jeweils genannten Gründen nicht barrierefrei.
22
+ {{/if}}
23
+
24
+ ## Nicht barrierefreie Inhalte
25
+
26
+ {{#if hasKnownIssues}}
27
+ {{#each compliance.knownIssues}}
28
+ - {{ description }}
29
+ {{#if standards}}
30
+ Betroffene Anforderung: {{ standards }}
31
+ {{/if}}
32
+ {{#if pageList}}
33
+ Betroffene Seiten: {{ pageList }}{{#if hasMorePages}} und {{ morePages }} weitere{{/if}}
34
+ {{/if}}
35
+ {{#if isDisproportionateBurden}}
36
+ Grund: unverhältnismäßige Belastung.
37
+ {{/if}}
38
+ {{#if isOutOfScope}}
39
+ Grund: der Inhalt fällt nicht in den Anwendungsbereich des BaFG.
40
+ {{/if}}
41
+ {{#if isFixPlanned}}
42
+ Grund: die Barriere ist bekannt und wird behoben.
43
+ {{/if}}
44
+ {{#if remedyByFormatted}}
45
+ Geplante Behebung bis: {{ remedyByFormatted }}
46
+ {{/if}}
47
+ {{#if isFromAudit}}
48
+ Automatisiert erkannt (axe-core, Regel {{ ruleId }}); bitte in eigenen Worten beschreiben.
49
+ {{/if}}
50
+ {{/each}}
51
+ {{/if}}
52
+ {{#if hasNoKnownIssues}}
53
+ Zum Zeitpunkt der Prüfung sind keine nicht barrierefreien Inhalte bekannt.
54
+ {{/if}}
55
+
56
+ ## Erstellung dieser Erklärung
57
+
58
+ Diese Erklärung wurde am {{ compliance.assessedOnFormatted }} erstellt.
59
+
60
+ {{#if compliance.isSelfAssessment}}
61
+ Grundlage ist eine Selbstbewertung durch {{ provider.legalName }}.
62
+ {{/if}}
63
+ {{#if compliance.isExternalAudit}}
64
+ Grundlage ist eine Prüfung durch Dritte.
65
+ {{/if}}
66
+
67
+ {{#if audit.isSinglePage}}
68
+ Die automatisierte Prüfung vom {{ audit.checkedOnFormatted }} umfasste eine Seite dieser
69
+ Website.
70
+ {{/if}}
71
+ {{#if audit.isMultiPage}}
72
+ Die automatisierte Prüfung vom {{ audit.checkedOnFormatted }} umfasste {{ audit.pages }}
73
+ Seiten dieser Website.
74
+ {{/if}}
75
+ {{#if audit.needsReviewIsSingle}}
76
+ Bei einer weiteren Regelprüfung ist eine manuelle Beurteilung erforderlich.
77
+ {{/if}}
78
+ {{#if audit.needsReviewIsPlural}}
79
+ Bei {{ audit.needsReview }} weiteren Regelprüfungen ist eine manuelle Beurteilung
80
+ erforderlich.
81
+ {{/if}}
82
+ {{#if audit.notEvaluatedIsSingle}}
83
+ Bei einer Regelprüfung erreichte das verwendete Werkzeug kein Ergebnis; sie wird nicht als
84
+ erfüllt ausgewiesen.
85
+ {{/if}}
86
+ {{#if audit.notEvaluatedIsPlural}}
87
+ Bei {{ audit.notEvaluated }} Regelprüfungen erreichte das verwendete Werkzeug kein
88
+ Ergebnis; sie werden nicht als erfüllt ausgewiesen.
89
+ {{/if}}
90
+ {{#if hasAudit}}
91
+
92
+ {{/if}}
93
+ Die Bewertung stützt sich unter anderem auf eine automatisierte Prüfung. Automatisierte
94
+ Werkzeuge erkennen nur einen Teil der möglichen Barrieren; sie ersetzen keine manuelle
95
+ Prüfung und keine Prüfung mit assistiven Technologien.
96
+
97
+ ## Feedback und Kontaktangaben
98
+
99
+ Sie haben eine Barriere gefunden oder benötigen Informationen in einer barrierefreien
100
+ Form? Melden Sie sich bitte bei uns:
101
+
102
+ - E-Mail: {{ provider.email }}
103
+ {{#if provider.feedbackUrl}}
104
+ - Kontaktformular: {{ provider.feedbackUrl }}
105
+ {{/if}}
106
+ {{#if provider.phone}}
107
+ - Telefon: {{ provider.phone }}
108
+ {{/if}}
109
+ {{#if provider.address}}
110
+ - Anschrift: {{ provider.address }}
111
+ {{/if}}
112
+
113
+ Wir bemühen uns, Ihre Rückmeldung zeitnah zu beantworten.
114
+
115
+ ## Beschwerdeverfahren
116
+
117
+ Wenn Sie mit unserer Antwort nicht zufrieden sind, können Sie sich an das
118
+ Sozialministeriumservice wenden. Das Sozialministeriumservice ist in Österreich die für
119
+ die Marktüberwachung nach dem BaFG zuständige Stelle.
120
+
121
+ Sozialministeriumservice
122
+ https://www.sozialministeriumservice.at
123
+
124
+ ---
125
+
126
+ Diese Erklärung wurde mit eaa-kit erstellt und ist keine Rechtsberatung. Prüfen Sie den
127
+ Inhalt vor der Veröffentlichung und lassen Sie ihn im Zweifel rechtlich prüfen.
@@ -0,0 +1,121 @@
1
+ # Accessibility Statement
2
+
3
+ {{ provider.legalName }} is committed to making the website {{ site.name }} accessible in
4
+ accordance with the Austrian Accessibility Act (Barrierefreiheitsgesetz, BaFG), which
5
+ transposes Directive (EU) 2019/882 (the European Accessibility Act) into Austrian law.
6
+
7
+ This accessibility statement applies to {{ site.url }}.
8
+
9
+ ## Compliance status
10
+
11
+ {{#if compliance.isCompliant}}
12
+ This website is fully compliant with {{ compliance.standard }}.
13
+ {{/if}}
14
+ {{#if compliance.isPartiallyCompliant}}
15
+ This website is partially compliant with {{ compliance.standard }}. The content listed in
16
+ the following section is not accessible, for the reasons given.
17
+ {{/if}}
18
+ {{#if compliance.isNonCompliant}}
19
+ This website is not compliant with {{ compliance.standard }}. The content listed in the
20
+ following section is not accessible, for the reasons given.
21
+ {{/if}}
22
+
23
+ ## Non-accessible content
24
+
25
+ {{#if hasKnownIssues}}
26
+ {{#each compliance.knownIssues}}
27
+ - {{ description }}
28
+ {{#if standards}}
29
+ Requirement affected: {{ standards }}
30
+ {{/if}}
31
+ {{#if pageList}}
32
+ Pages affected: {{ pageList }}{{#if hasMorePages}} and {{ morePages }} more{{/if}}
33
+ {{/if}}
34
+ {{#if isDisproportionateBurden}}
35
+ Reason: disproportionate burden.
36
+ {{/if}}
37
+ {{#if isOutOfScope}}
38
+ Reason: the content falls outside the scope of the BaFG.
39
+ {{/if}}
40
+ {{#if isFixPlanned}}
41
+ Reason: the barrier is known and is being addressed.
42
+ {{/if}}
43
+ {{#if remedyByFormatted}}
44
+ Expected to be resolved by: {{ remedyByFormatted }}
45
+ {{/if}}
46
+ {{#if isFromAudit}}
47
+ Detected by automated testing (axe-core, rule {{ ruleId }}); describe it in your own words.
48
+ {{/if}}
49
+ {{/each}}
50
+ {{/if}}
51
+ {{#if hasNoKnownIssues}}
52
+ No non-accessible content was known at the time of assessment.
53
+ {{/if}}
54
+
55
+ ## Preparation of this statement
56
+
57
+ This statement was prepared on {{ compliance.assessedOnFormatted }}.
58
+
59
+ {{#if compliance.isSelfAssessment}}
60
+ It is based on a self-assessment carried out by {{ provider.legalName }}.
61
+ {{/if}}
62
+ {{#if compliance.isExternalAudit}}
63
+ It is based on an assessment carried out by a third party.
64
+ {{/if}}
65
+
66
+ {{#if audit.isSinglePage}}
67
+ The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
68
+ {{/if}}
69
+ {{#if audit.isMultiPage}}
70
+ The automated test run of {{ audit.checkedOnFormatted }} covered {{ audit.pages }}
71
+ pages of this website.
72
+ {{/if}}
73
+ {{#if audit.needsReviewIsSingle}}
74
+ One further rule check requires a manual decision.
75
+ {{/if}}
76
+ {{#if audit.needsReviewIsPlural}}
77
+ {{ audit.needsReview }} further rule checks require a manual decision.
78
+ {{/if}}
79
+ {{#if audit.notEvaluatedIsSingle}}
80
+ One rule check could not be decided by the tool that was used; it is not reported as met.
81
+ {{/if}}
82
+ {{#if audit.notEvaluatedIsPlural}}
83
+ {{ audit.notEvaluated }} rule checks could not be decided by the tool that was used; they
84
+ are not reported as met.
85
+ {{/if}}
86
+ {{#if hasAudit}}
87
+
88
+ {{/if}}
89
+ The assessment relies in part on automated testing. Automated tools detect only a subset
90
+ of possible barriers; they are not a substitute for manual testing or for testing with
91
+ assistive technologies.
92
+
93
+ ## Feedback and contact
94
+
95
+ Found a barrier, or need information in an accessible format? Please get in touch:
96
+
97
+ - Email: {{ provider.email }}
98
+ {{#if provider.feedbackUrl}}
99
+ - Contact form: {{ provider.feedbackUrl }}
100
+ {{/if}}
101
+ {{#if provider.phone}}
102
+ - Phone: {{ provider.phone }}
103
+ {{/if}}
104
+ {{#if provider.address}}
105
+ - Address: {{ provider.address }}
106
+ {{/if}}
107
+
108
+ We aim to respond to your feedback promptly.
109
+
110
+ ## Enforcement procedure
111
+
112
+ If you are not satisfied with our response, you can contact the Sozialministeriumservice,
113
+ the authority responsible for market surveillance under the BaFG in Austria.
114
+
115
+ Sozialministeriumservice
116
+ https://www.sozialministeriumservice.at
117
+
118
+ ---
119
+
120
+ This statement was generated with eaa-kit and is not legal advice. Review it before
121
+ publishing, and have it checked by a lawyer if in doubt.