@owlmeans/web-consent 0.1.18-rc.44 → 0.1.18-rc.46
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.
- package/README.md +4 -4
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/web-consent/SKILL.md +5 -4
- package/build/consent/bar.d.ts +1 -1
- package/build/consent/bar.js +2 -2
- package/build/consent/bar.js.map +1 -1
- package/build/consent/locating.d.ts +1 -1
- package/build/consent/locating.js +1 -1
- package/build/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/consent/bar.tsx +2 -2
- package/src/consent/locating.tsx +1 -1
- package/src/types.ts +1 -1
- package/tests/bar.spec.ts +15 -7
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ The `web-consent` skill covers the components, the `consent` skill the model beh
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
bun add @owlmeans/web-consent@^0.1.18-rc.
|
|
17
|
+
bun add @owlmeans/web-consent@^0.1.18-rc.46
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Peer dependencies the app provides: `react`, `tailwindcss`, `tailwind-merge`, `clsx`, `lucide-react`.
|
|
@@ -49,7 +49,7 @@ Tailwind entry must scan the package's `src`:
|
|
|
49
49
|
|
|
50
50
|
At the application root or layout. It opens itself when no decision is stored and renders only the
|
|
51
51
|
re-open button once one is. A first-time visitor is asked with a tall bar across the bottom of a
|
|
52
|
-
|
|
52
|
+
dimmed overlay — "Cookie preferences", "Accept only mandatory", "Accept all" — and every later
|
|
53
53
|
opening is the preferences window; `mode="window"` asks with the window straight away.
|
|
54
54
|
|
|
55
55
|
```tsx
|
|
@@ -186,7 +186,7 @@ re-exported; import them from `@owlmeans/consent`.
|
|
|
186
186
|
| Selector | Element |
|
|
187
187
|
|---|---|
|
|
188
188
|
| `[data-consent-dialog]` | whichever surface asks — the bar or the window (`data-consent-mode="bar\|window"`) |
|
|
189
|
-
| `[data-consent-bar]`, `[data-consent-overlay]` | the bar, and the
|
|
189
|
+
| `[data-consent-bar]`, `[data-consent-overlay]` | the bar, and the dimmed overlay it sits on |
|
|
190
190
|
| `[data-consent-preferences]`, `[data-consent-mandatory]`, `[data-consent-accept-all]` | the bar's three answers |
|
|
191
191
|
| `[data-consent-save]`, `[data-consent-accept-all]` | the window's two actions |
|
|
192
192
|
| `[data-consent-locating="first"]`, `[data-consent-spinner]` | the locating overlay and its spinner |
|
|
@@ -230,7 +230,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
230
230
|
your project's skill store (`.agents/skills/`):
|
|
231
231
|
|
|
232
232
|
```sh
|
|
233
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
233
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.55
|
|
234
234
|
```
|
|
235
235
|
|
|
236
236
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/web-consent",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.46",
|
|
5
|
+
"generatedAt": "2026-10-16T22:27:59.065Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/web-consent
|
|
9
9
|
|
|
10
10
|
**Layer:** Web (React)
|
|
11
|
-
**Install:** `"@owlmeans/web-consent": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/web-consent": "^0.1.18-rc.46"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
The browser components of the consent set. The model — categories, storage, migration, the store,
|
|
14
14
|
Consent Mode signalling — is `@owlmeans/consent`, and this package re-exports a **named selection**
|
|
@@ -108,8 +108,8 @@ import { CookieConsent } from '@owlmeans/web-consent'
|
|
|
108
108
|
|
|
109
109
|
## The bar
|
|
110
110
|
|
|
111
|
-
A tall bar across the bottom of a **
|
|
112
|
-
`fixed inset-0 bg-
|
|
111
|
+
A tall bar across the bottom of a **dimmed** overlay (`[data-consent-overlay]`,
|
|
112
|
+
`fixed inset-0 bg-black/70`): the page stays in sight and scrolls, but nothing on it can be
|
|
113
113
|
pressed until the visitor answers. The bar (`fixed inset-x-0 bottom-0 max-h-[85vh] border-t
|
|
114
114
|
bg-background`) holds, left to right on a wide screen and stacked on a phone:
|
|
115
115
|
|
|
@@ -140,7 +140,8 @@ follow the flat rule those apps are held to: **no gradient, shadow, glow, glass
|
|
|
140
140
|
|
|
141
141
|
| Part | Classes |
|
|
142
142
|
|---|---|
|
|
143
|
-
| Bar overlay
|
|
143
|
+
| Bar overlay | `bg-black/70`, matching the preferences window — the page is dimmed beneath the opaque bar |
|
|
144
|
+
| Locating overlay | `bg-transparent` — a quick region lookup flashes no backdrop |
|
|
144
145
|
| Bar | `border-t border-border bg-background text-foreground`, no shadow |
|
|
145
146
|
| Bar answers | "Accept only mandatory" and "Accept All" both the accent pill; "Cookie preferences" outlined |
|
|
146
147
|
| Spinner | `text-muted-foreground motion-safe:animate-spin` |
|
package/build/consent/bar.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ConsentBarProps } from './types.local.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* The first question a visitor is asked, as a tall bar across the bottom of the page.
|
|
5
5
|
*
|
|
6
|
-
* It sits on a
|
|
6
|
+
* It sits on a dimmed overlay: the page stays in sight and scrolls, but nothing on it can be
|
|
7
7
|
* pressed until the visitor answers. The text says what the essential cookies do, names the
|
|
8
8
|
* optional categories in force (as a list after a colon, so no language has to decline a label),
|
|
9
9
|
* that they stay off until allowed, and that the choice can be changed or withdrawn — then the
|
package/build/consent/bar.js
CHANGED
|
@@ -9,7 +9,7 @@ import { ConsentLinks } from './links.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* The first question a visitor is asked, as a tall bar across the bottom of the page.
|
|
11
11
|
*
|
|
12
|
-
* It sits on a
|
|
12
|
+
* It sits on a dimmed overlay: the page stays in sight and scrolls, but nothing on it can be
|
|
13
13
|
* pressed until the visitor answers. The text says what the essential cookies do, names the
|
|
14
14
|
* optional categories in force (as a list after a colon, so no language has to decline a label),
|
|
15
15
|
* that they stay off until allowed, and that the choice can be changed or withdrawn — then the
|
|
@@ -32,6 +32,6 @@ export const ConsentBar = props => {
|
|
|
32
32
|
const description = optional.length > 0
|
|
33
33
|
? consentI18nHelper.interpolate(t('barDescription', 'We use essential cookies to make this site work — for signing in, security and remembering your choices. With your consent we would also use these optional cookies: {{categories}}. They stay off until you allow them, and you can change or withdraw your choice at any time in the cookie preferences.'), { categories: optional.map(category => t(category.labelKey, category.key)).join(', ') })
|
|
34
34
|
: t('barDescriptionEssential', 'This site uses only essential cookies — for signing in, security and remembering your choices. They need no consent and cannot be switched off.');
|
|
35
|
-
return _jsx("div", { className: "fixed inset-0 z-[999998] bg-
|
|
35
|
+
return _jsx("div", { className: "fixed inset-0 z-[999998] bg-black/70", "data-consent-overlay": true, children: _jsx("div", { ref: surface, tabIndex: -1, className: webConsentUtils.cn('fixed inset-x-0 bottom-0 z-[999999] max-h-[85vh] overflow-y-auto border-t border-border bg-background text-foreground outline-none', props.barClassName), role: "dialog", "aria-modal": "true", "aria-labelledby": "cc-bar-title", "aria-describedby": domains.length > 1 ? 'cc-bar-desc cc-bar-domains' : 'cc-bar-desc', "data-consent-dialog": true, "data-consent-bar": true, "data-consent-mode": "bar", children: _jsxs("div", { className: "mx-auto flex max-w-6xl flex-col gap-6 px-4 py-6 sm:px-8 sm:py-8 lg:flex-row lg:items-end lg:gap-10", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-3 flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-muted text-primary", children: _jsx(Cookie, { className: "h-5 w-5", "aria-hidden": "true" }) }), _jsx("h2", { id: "cc-bar-title", className: "text-balance text-lg font-extrabold tracking-tight text-foreground sm:text-xl", children: t('barTitle', 'Cookies on this site') })] }), _jsx("p", { id: "cc-bar-desc", className: "text-pretty text-sm leading-relaxed text-muted-foreground", children: description }), domains.length > 1 && _jsx("p", { id: "cc-bar-domains", "data-consent-domains": true, className: "mt-2 text-pretty text-xs text-muted-foreground", children: consentI18nHelper.interpolate(t('domains', 'This choice applies to {{domains}}.'), { domains: domains.join(', ') }) }), _jsx(ConsentLinks, { t: t, policyHref: props.policyHref, links: props.links, className: "mt-1" })] }), _jsxs("div", { className: "flex w-full flex-col gap-3 sm:flex-row sm:flex-wrap sm:justify-end lg:w-auto lg:max-w-xl lg:flex-shrink-0", children: [_jsx("button", { type: "button", onClick: props.onPreferences, "data-consent-preferences": true, className: webConsentUtils.cn(BAR_PILL, OUTLINED), children: t('openPreferences', 'Cookie preferences') }), optional.length > 0 && _jsx("button", { type: "button", onClick: props.onMandatory, "data-consent-mandatory": true, className: webConsentUtils.cn(BAR_PILL, ACCENT), children: t('acceptMandatory', 'Accept only mandatory') }), _jsx("button", { type: "button", onClick: props.onAcceptAll, "data-consent-accept-all": true, className: webConsentUtils.cn(BAR_PILL, ACCENT), children: t('acceptAll', 'Accept All') })] })] }) }) });
|
|
36
36
|
};
|
|
37
37
|
//# sourceMappingURL=bar.js.map
|
package/build/consent/bar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bar.js","sourceRoot":"","sources":["../../src/consent/bar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAW,MAAM,OAAO,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGzC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAwB,KAAK,CAAC,EAAE;IACrD,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,KAAK,CAAA;IACxC,MAAM,OAAO,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC5C,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAE9B,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAA;IAC1E,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;QACrC,CAAC,CAAC,iBAAiB,CAAC,WAAW,CAC7B,CAAC,CAAC,gBAAgB,EAAE,4SAA4S,CAAC,EACjU,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxF;QACD,CAAC,CAAC,CAAC,CAAC,yBAAyB,EAAE,iJAAiJ,CAAC,CAAA;IAEnL,OAAO,cAAK,SAAS,EAAC,
|
|
1
|
+
{"version":3,"file":"bar.js","sourceRoot":"","sources":["../../src/consent/bar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type FC } from 'react';
|
|
2
2
|
import type { ConsentLocatingProps } from './types.local.js';
|
|
3
3
|
/**
|
|
4
|
-
* While the visitor's country is being found:
|
|
4
|
+
* While the visitor's country is being found: a transparent overlay — the
|
|
5
5
|
* page stays in sight and out of reach — with a spinner and no bar. The spinner itself waits
|
|
6
6
|
* `CONSENT_LOCATING_DELAY`, so an answer from the edge in a few milliseconds flashes nothing; the
|
|
7
7
|
* status text is there from the start for assistive technology.
|
|
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
|
|
|
3
3
|
import { LoaderCircle } from 'lucide-react';
|
|
4
4
|
import { CONSENT_LOCATING_DELAY } from './consts.local.js';
|
|
5
5
|
/**
|
|
6
|
-
* While the visitor's country is being found:
|
|
6
|
+
* While the visitor's country is being found: a transparent overlay — the
|
|
7
7
|
* page stays in sight and out of reach — with a spinner and no bar. The spinner itself waits
|
|
8
8
|
* `CONSENT_LOCATING_DELAY`, so an answer from the edge in a few milliseconds flashes nothing; the
|
|
9
9
|
* status text is there from the start for assistive technology.
|
package/build/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConsentCategory, ConsentGeoOptions, ConsentLinkerOptions, ConsentLocating, ConsentReason, ConsentRecord, ConsentService } from '@owlmeans/consent';
|
|
2
2
|
/**
|
|
3
|
-
* How a first-time visitor is asked: `bar` — a tall bar across the bottom of a
|
|
3
|
+
* How a first-time visitor is asked: `bar` — a tall bar across the bottom of a dimmed overlay
|
|
4
4
|
* that blocks the page but leaves it in sight, with "Cookie preferences", "Accept only mandatory" and
|
|
5
5
|
* "Accept all" — or `window`, the preferences window straight away. Either way every later opening
|
|
6
6
|
* (the bar's own "Cookie preferences", a footer link, the corner button, the sign-in gate) is the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/web-consent",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.46",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@owlmeans/dep-config": "workspace:*",
|
|
36
|
-
"@owlmeans/test-ui": "^0.1.18-rc.
|
|
36
|
+
"@owlmeans/test-ui": "^0.1.18-rc.53",
|
|
37
37
|
"@tailwindcss/vite": "^4.3.3",
|
|
38
38
|
"@types/bun": "^1.4.2",
|
|
39
39
|
"@types/react": "^19.3.0",
|
package/src/consent/bar.tsx
CHANGED
|
@@ -10,7 +10,7 @@ import type { ConsentBarProps } from './types.local.js'
|
|
|
10
10
|
/**
|
|
11
11
|
* The first question a visitor is asked, as a tall bar across the bottom of the page.
|
|
12
12
|
*
|
|
13
|
-
* It sits on a
|
|
13
|
+
* It sits on a dimmed overlay: the page stays in sight and scrolls, but nothing on it can be
|
|
14
14
|
* pressed until the visitor answers. The text says what the essential cookies do, names the
|
|
15
15
|
* optional categories in force (as a list after a colon, so no language has to decline a label),
|
|
16
16
|
* that they stay off until allowed, and that the choice can be changed or withdrawn — then the
|
|
@@ -38,7 +38,7 @@ export const ConsentBar: FC<ConsentBarProps> = props => {
|
|
|
38
38
|
)
|
|
39
39
|
: t('barDescriptionEssential', 'This site uses only essential cookies — for signing in, security and remembering your choices. They need no consent and cannot be switched off.')
|
|
40
40
|
|
|
41
|
-
return <div className="fixed inset-0 z-[999998] bg-
|
|
41
|
+
return <div className="fixed inset-0 z-[999998] bg-black/70" data-consent-overlay>
|
|
42
42
|
<div
|
|
43
43
|
ref={surface} tabIndex={-1}
|
|
44
44
|
className={webConsentUtils.cn(
|
package/src/consent/locating.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { CONSENT_LOCATING_DELAY } from './consts.local.js'
|
|
|
4
4
|
import type { ConsentLocatingProps } from './types.local.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* While the visitor's country is being found:
|
|
7
|
+
* While the visitor's country is being found: a transparent overlay — the
|
|
8
8
|
* page stays in sight and out of reach — with a spinner and no bar. The spinner itself waits
|
|
9
9
|
* `CONSENT_LOCATING_DELAY`, so an answer from the edge in a few milliseconds flashes nothing; the
|
|
10
10
|
* status text is there from the start for assistive technology.
|
package/src/types.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
} from '@owlmeans/consent'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* How a first-time visitor is asked: `bar` — a tall bar across the bottom of a
|
|
7
|
+
* How a first-time visitor is asked: `bar` — a tall bar across the bottom of a dimmed overlay
|
|
8
8
|
* that blocks the page but leaves it in sight, with "Cookie preferences", "Accept only mandatory" and
|
|
9
9
|
* "Accept all" — or `window`, the preferences window straight away. Either way every later opening
|
|
10
10
|
* (the bar's own "Cookie preferences", a footer link, the corner button, the sign-in gate) is the
|
package/tests/bar.spec.ts
CHANGED
|
@@ -107,7 +107,7 @@ describe('@owlmeans/web-consent — the bar', () => {
|
|
|
107
107
|
}
|
|
108
108
|
}, TIMEOUT)
|
|
109
109
|
|
|
110
|
-
test('the bar is flat, sits on a
|
|
110
|
+
test('the bar is flat, sits on a dimmed overlay, and both answers are equally prominent', async () => {
|
|
111
111
|
const { page, close } = await mountComponent({ url: `${base}/` })
|
|
112
112
|
try {
|
|
113
113
|
const bar = page.locator('[data-consent-bar]')
|
|
@@ -117,7 +117,7 @@ describe('@owlmeans/web-consent — the bar', () => {
|
|
|
117
117
|
.map(element => element.getAttribute('class') ?? '').join(' '))
|
|
118
118
|
|
|
119
119
|
expect(classes).not.toMatch(/\b(?:bg-gradient|from-|to-secondary|backdrop-|blur|shadow|ring-primary)/)
|
|
120
|
-
expect(await overlay.getAttribute('class')).
|
|
120
|
+
expect(await overlay.getAttribute('class')).toContain('bg-black/70')
|
|
121
121
|
expect(await overlay.getAttribute('class')).toMatch(/\binset-0\b/)
|
|
122
122
|
expect(await bar.getAttribute('class')).toMatch(/\bbottom-0\b/)
|
|
123
123
|
expect(await bar.getAttribute('class')).toMatch(/\bbg-background\b/)
|
|
@@ -141,8 +141,8 @@ describe('@owlmeans/web-consent — the bar', () => {
|
|
|
141
141
|
}
|
|
142
142
|
}, TIMEOUT)
|
|
143
143
|
|
|
144
|
-
test('styled: the page
|
|
145
|
-
const { page, close } = await mountComponent({ url: `${base}/?styled=1` })
|
|
144
|
+
test.each(['light', 'dark'])('styled (%s): the page is dimmed and out of reach, the bar sits at the very bottom', async theme => {
|
|
145
|
+
const { page, close } = await mountComponent({ url: `${base}/?styled=1&theme=${theme}` })
|
|
146
146
|
try {
|
|
147
147
|
const bar = page.locator('[data-consent-bar]')
|
|
148
148
|
await bar.waitFor()
|
|
@@ -153,15 +153,23 @@ describe('@owlmeans/web-consent — the bar', () => {
|
|
|
153
153
|
expect(Math.round(box.width)).toBe(viewport.width)
|
|
154
154
|
const blocked = await page.evaluate(() => {
|
|
155
155
|
const hit = document.elementFromPoint(10, 10)
|
|
156
|
+
const canvas = document.createElement('canvas')
|
|
157
|
+
canvas.width = canvas.height = 1
|
|
158
|
+
const context = canvas.getContext('2d')!
|
|
159
|
+
context.fillStyle = hit == null ? 'transparent' : getComputedStyle(hit).backgroundColor
|
|
160
|
+
context.fillRect(0, 0, 1, 1)
|
|
156
161
|
|
|
157
162
|
return {
|
|
158
163
|
overlay: hit?.closest('[data-consent-overlay]') != null,
|
|
159
|
-
background:
|
|
164
|
+
background: Array.from(context.getImageData(0, 0, 1, 1).data),
|
|
165
|
+
opacity: hit == null ? null : getComputedStyle(hit).opacity,
|
|
160
166
|
}
|
|
161
167
|
})
|
|
162
|
-
//
|
|
168
|
+
// Dim the page with the same translucent black as the preferences window, in both themes.
|
|
163
169
|
expect(blocked.overlay).toBe(true)
|
|
164
|
-
expect(blocked.background).
|
|
170
|
+
expect(blocked.background).toEqual([0, 0, 0, 179])
|
|
171
|
+
expect(blocked.opacity).toBe('1')
|
|
172
|
+
expect(await bar.evaluate(root => getComputedStyle(root).opacity)).toBe('1')
|
|
165
173
|
// The remount button under the overlay cannot be pressed.
|
|
166
174
|
await expect(page.locator('#remount').click({ timeout: 1_000 })).rejects.toThrow()
|
|
167
175
|
} finally {
|