496 lines
19 KiB
JavaScript
496 lines
19 KiB
JavaScript
import { jsx as C } from "react/jsx-runtime";
|
|
import S from "react";
|
|
import { o as P } from "./create-component-CVXl33PD.mjs";
|
|
import { _ as o, n as u, r as $, x as O, c as L, E as h, a as N, b as z } from "./class-map-CwiboTfb.mjs";
|
|
import "./divider-Diu_1O5h.mjs";
|
|
import { E as b, r as g, a as l } from "./animation-DjClVFum.mjs";
|
|
import { m as H } from "./delegate-BXi1gVeU.mjs";
|
|
import { r as _ } from "./redispatch-event-taWUbWUt.mjs";
|
|
/**
|
|
* @license
|
|
* Copyright 2023 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
const M = {
|
|
dialog: [
|
|
[
|
|
// Dialog slide down
|
|
[{ transform: "translateY(-50px)" }, { transform: "translateY(0)" }],
|
|
{ duration: 500, easing: b.EMPHASIZED }
|
|
]
|
|
],
|
|
scrim: [
|
|
[
|
|
// Scrim fade in
|
|
[{ opacity: 0 }, { opacity: 0.32 }],
|
|
{ duration: 500, easing: "linear" }
|
|
]
|
|
],
|
|
container: [
|
|
[
|
|
// Container fade in
|
|
[{ opacity: 0 }, { opacity: 1 }],
|
|
{ duration: 50, easing: "linear", pseudoElement: "::before" }
|
|
],
|
|
[
|
|
// Container grow
|
|
// Note: current spec says to grow from 0dp->100% and shrink from
|
|
// 100%->35%. We change this to 35%->100% to simplify the animation that
|
|
// is supposed to clip content as it grows. From 0dp it's possible to see
|
|
// text/actions appear before the container has fully grown.
|
|
[{ height: "35%" }, { height: "100%" }],
|
|
{ duration: 500, easing: b.EMPHASIZED, pseudoElement: "::before" }
|
|
]
|
|
],
|
|
headline: [
|
|
[
|
|
// Headline fade in
|
|
[{ opacity: 0 }, { opacity: 0, offset: 0.2 }, { opacity: 1 }],
|
|
{ duration: 250, easing: "linear", fill: "forwards" }
|
|
]
|
|
],
|
|
content: [
|
|
[
|
|
// Content fade in
|
|
[{ opacity: 0 }, { opacity: 0, offset: 0.2 }, { opacity: 1 }],
|
|
{ duration: 250, easing: "linear", fill: "forwards" }
|
|
]
|
|
],
|
|
actions: [
|
|
[
|
|
// Actions fade in
|
|
[{ opacity: 0 }, { opacity: 0, offset: 0.5 }, { opacity: 1 }],
|
|
{ duration: 300, easing: "linear", fill: "forwards" }
|
|
]
|
|
]
|
|
}, V = {
|
|
dialog: [
|
|
[
|
|
// Dialog slide up
|
|
[{ transform: "translateY(0)" }, { transform: "translateY(-50px)" }],
|
|
{ duration: 150, easing: b.EMPHASIZED_ACCELERATE }
|
|
]
|
|
],
|
|
scrim: [
|
|
[
|
|
// Scrim fade out
|
|
[{ opacity: 0.32 }, { opacity: 0 }],
|
|
{ duration: 150, easing: "linear" }
|
|
]
|
|
],
|
|
container: [
|
|
[
|
|
// Container shrink
|
|
[{ height: "100%" }, { height: "35%" }],
|
|
{
|
|
duration: 150,
|
|
easing: b.EMPHASIZED_ACCELERATE,
|
|
pseudoElement: "::before"
|
|
}
|
|
],
|
|
[
|
|
// Container fade out
|
|
[{ opacity: "1" }, { opacity: "0" }],
|
|
{ delay: 100, duration: 50, easing: "linear", pseudoElement: "::before" }
|
|
]
|
|
],
|
|
headline: [
|
|
[
|
|
// Headline fade out
|
|
[{ opacity: 1 }, { opacity: 0 }],
|
|
{ duration: 100, easing: "linear", fill: "forwards" }
|
|
]
|
|
],
|
|
content: [
|
|
[
|
|
// Content fade out
|
|
[{ opacity: 1 }, { opacity: 0 }],
|
|
{ duration: 100, easing: "linear", fill: "forwards" }
|
|
]
|
|
],
|
|
actions: [
|
|
[
|
|
// Actions fade out
|
|
[{ opacity: 1 }, { opacity: 0 }],
|
|
{ duration: 100, easing: "linear", fill: "forwards" }
|
|
]
|
|
]
|
|
};
|
|
/**
|
|
* @license
|
|
* Copyright 2023 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
const W = H($);
|
|
let s = class extends W {
|
|
// We do not use `delegatesFocus: true` due to a Chromium bug with
|
|
// selecting text.
|
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=950357
|
|
/**
|
|
* Opens the dialog when set to `true` and closes it when set to `false`.
|
|
*/
|
|
get open() {
|
|
return this.isOpen;
|
|
}
|
|
set open(e) {
|
|
e !== this.isOpen && (this.isOpen = e, e ? (this.setAttribute("open", ""), this.show()) : (this.removeAttribute("open"), this.close()));
|
|
}
|
|
constructor() {
|
|
super(), this.quick = !1, this.returnValue = "", this.noFocusTrap = !1, this.getOpenAnimation = () => M, this.getCloseAnimation = () => V, this.isOpen = !1, this.isOpening = !1, this.isConnectedPromise = this.getIsConnectedPromise(), this.isAtScrollTop = !1, this.isAtScrollBottom = !1, this.nextClickIsFromContent = !1, this.hasHeadline = !1, this.hasActions = !1, this.hasIcon = !1, this.escapePressedWithoutCancel = !1, this.treewalker = document.createTreeWalker(this, NodeFilter.SHOW_ELEMENT), this.addEventListener("submit", this.handleSubmit);
|
|
}
|
|
/**
|
|
* Opens the dialog and fires a cancelable `open` event. After a dialog's
|
|
* animation, an `opened` event is fired.
|
|
*
|
|
* Add an `autofocus` attribute to a child of the dialog that should
|
|
* receive focus after opening.
|
|
*
|
|
* @return A Promise that resolves after the animation is finished and the
|
|
* `opened` event was fired.
|
|
*/
|
|
async show() {
|
|
var i;
|
|
this.isOpening = !0, await this.isConnectedPromise, await this.updateComplete;
|
|
const e = this.dialog;
|
|
if (e.open || !this.isOpening) {
|
|
this.isOpening = !1;
|
|
return;
|
|
}
|
|
if (!this.dispatchEvent(new Event("open", { cancelable: !0 }))) {
|
|
this.open = !1, this.isOpening = !1;
|
|
return;
|
|
}
|
|
e.showModal(), this.open = !0, this.scroller && (this.scroller.scrollTop = 0), (i = this.querySelector("[autofocus]")) == null || i.focus(), await this.animateDialog(this.getOpenAnimation()), this.dispatchEvent(new Event("opened")), this.isOpening = !1;
|
|
}
|
|
/**
|
|
* Closes the dialog and fires a cancelable `close` event. After a dialog's
|
|
* animation, a `closed` event is fired.
|
|
*
|
|
* @param returnValue A return value usually indicating which button was used
|
|
* to close a dialog. If a dialog is canceled by clicking the scrim or
|
|
* pressing Escape, it will not change the return value after closing.
|
|
* @return A Promise that resolves after the animation is finished and the
|
|
* `closed` event was fired.
|
|
*/
|
|
async close(e = this.returnValue) {
|
|
if (this.isOpening = !1, !this.isConnected) {
|
|
this.open = !1;
|
|
return;
|
|
}
|
|
await this.updateComplete;
|
|
const t = this.dialog;
|
|
if (!t.open || this.isOpening) {
|
|
this.open = !1;
|
|
return;
|
|
}
|
|
const i = this.returnValue;
|
|
if (this.returnValue = e, !this.dispatchEvent(new Event("close", { cancelable: !0 }))) {
|
|
this.returnValue = i;
|
|
return;
|
|
}
|
|
await this.animateDialog(this.getCloseAnimation()), t.close(e), this.open = !1, this.dispatchEvent(new Event("closed"));
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this.isConnectedPromiseResolve();
|
|
}
|
|
disconnectedCallback() {
|
|
super.disconnectedCallback(), this.isConnectedPromise = this.getIsConnectedPromise();
|
|
}
|
|
render() {
|
|
const e = this.open && !(this.isAtScrollTop && this.isAtScrollBottom), t = {
|
|
"has-headline": this.hasHeadline,
|
|
"has-actions": this.hasActions,
|
|
"has-icon": this.hasIcon,
|
|
scrollable: e,
|
|
"show-top-divider": e && !this.isAtScrollTop,
|
|
"show-bottom-divider": e && !this.isAtScrollBottom
|
|
}, i = this.open && !this.noFocusTrap, a = O`
|
|
<div
|
|
class="focus-trap"
|
|
tabindex="0"
|
|
aria-hidden="true"
|
|
@focus=${this.handleFocusTrapFocus}></div>
|
|
`, { ariaLabel: r } = this;
|
|
return O`
|
|
<div class="scrim"></div>
|
|
<dialog
|
|
class=${L(t)}
|
|
aria-label=${r || h}
|
|
aria-labelledby=${this.hasHeadline ? "headline" : h}
|
|
role=${this.type === "alert" ? "alertdialog" : h}
|
|
@cancel=${this.handleCancel}
|
|
@click=${this.handleDialogClick}
|
|
@close=${this.handleClose}
|
|
@keydown=${this.handleKeydown}
|
|
.returnValue=${this.returnValue || h}>
|
|
${i ? a : h}
|
|
<div class="container" @click=${this.handleContentClick}>
|
|
<div class="headline">
|
|
<div class="icon" aria-hidden="true">
|
|
<slot name="icon" @slotchange=${this.handleIconChange}></slot>
|
|
</div>
|
|
<h2 id="headline" aria-hidden=${!this.hasHeadline || h}>
|
|
<slot
|
|
name="headline"
|
|
@slotchange=${this.handleHeadlineChange}></slot>
|
|
</h2>
|
|
<md-divider></md-divider>
|
|
</div>
|
|
<div class="scroller">
|
|
<div class="content">
|
|
<div class="top anchor"></div>
|
|
<slot name="content"></slot>
|
|
<div class="bottom anchor"></div>
|
|
</div>
|
|
</div>
|
|
<div class="actions">
|
|
<md-divider></md-divider>
|
|
<slot name="actions" @slotchange=${this.handleActionsChange}></slot>
|
|
</div>
|
|
</div>
|
|
${i ? a : h}
|
|
</dialog>
|
|
`;
|
|
}
|
|
firstUpdated() {
|
|
this.intersectionObserver = new IntersectionObserver((e) => {
|
|
for (const t of e)
|
|
this.handleAnchorIntersection(t);
|
|
}, { root: this.scroller }), this.intersectionObserver.observe(this.topAnchor), this.intersectionObserver.observe(this.bottomAnchor);
|
|
}
|
|
handleDialogClick() {
|
|
if (this.nextClickIsFromContent) {
|
|
this.nextClickIsFromContent = !1;
|
|
return;
|
|
}
|
|
this.dispatchEvent(new Event("cancel", { cancelable: !0 })) && this.close();
|
|
}
|
|
handleContentClick() {
|
|
this.nextClickIsFromContent = !0;
|
|
}
|
|
handleSubmit(e) {
|
|
const t = e.target, { submitter: i } = e;
|
|
t.method !== "dialog" || !i || this.close(i.getAttribute("value") ?? this.returnValue);
|
|
}
|
|
handleCancel(e) {
|
|
if (e.target !== this.dialog)
|
|
return;
|
|
this.escapePressedWithoutCancel = !1;
|
|
const t = !_(this, e);
|
|
e.preventDefault(), !t && this.close();
|
|
}
|
|
handleClose() {
|
|
var e;
|
|
this.escapePressedWithoutCancel && (this.escapePressedWithoutCancel = !1, (e = this.dialog) == null || e.dispatchEvent(new Event("cancel", { cancelable: !0 })));
|
|
}
|
|
handleKeydown(e) {
|
|
e.key === "Escape" && (this.escapePressedWithoutCancel = !0, setTimeout(() => {
|
|
this.escapePressedWithoutCancel = !1;
|
|
}));
|
|
}
|
|
async animateDialog(e) {
|
|
var k;
|
|
if ((k = this.cancelAnimations) == null || k.abort(), this.cancelAnimations = new AbortController(), this.quick)
|
|
return;
|
|
const { dialog: t, scrim: i, container: a, headline: r, content: d, actions: c } = this;
|
|
if (!t || !i || !a || !r || !d || !c)
|
|
return;
|
|
const { container: p, dialog: f, scrim: v, headline: m, content: w, actions: A } = e, E = [
|
|
[t, f ?? []],
|
|
[i, v ?? []],
|
|
[a, p ?? []],
|
|
[r, m ?? []],
|
|
[d, w ?? []],
|
|
[c, A ?? []]
|
|
], y = [];
|
|
for (const [F, I] of E)
|
|
for (const D of I) {
|
|
const T = F.animate(...D);
|
|
this.cancelAnimations.signal.addEventListener("abort", () => {
|
|
T.cancel();
|
|
}), y.push(T);
|
|
}
|
|
await Promise.all(y.map((F) => F.finished.catch(() => {
|
|
})));
|
|
}
|
|
handleHeadlineChange(e) {
|
|
const t = e.target;
|
|
this.hasHeadline = t.assignedElements().length > 0;
|
|
}
|
|
handleActionsChange(e) {
|
|
const t = e.target;
|
|
this.hasActions = t.assignedElements().length > 0;
|
|
}
|
|
handleIconChange(e) {
|
|
const t = e.target;
|
|
this.hasIcon = t.assignedElements().length > 0;
|
|
}
|
|
handleAnchorIntersection(e) {
|
|
const { target: t, isIntersecting: i } = e;
|
|
t === this.topAnchor && (this.isAtScrollTop = i), t === this.bottomAnchor && (this.isAtScrollBottom = i);
|
|
}
|
|
getIsConnectedPromise() {
|
|
return new Promise((e) => {
|
|
this.isConnectedPromiseResolve = e;
|
|
});
|
|
}
|
|
handleFocusTrapFocus(e) {
|
|
var m;
|
|
const [t, i] = this.getFirstAndLastFocusableChildren();
|
|
if (!t || !i) {
|
|
(m = this.dialog) == null || m.focus();
|
|
return;
|
|
}
|
|
const a = e.target === this.firstFocusTrap, r = !a, d = e.relatedTarget === t, c = e.relatedTarget === i, p = !d && !c;
|
|
if (r && c || a && p) {
|
|
t.focus();
|
|
return;
|
|
}
|
|
if (a && d || r && p) {
|
|
i.focus();
|
|
return;
|
|
}
|
|
}
|
|
getFirstAndLastFocusableChildren() {
|
|
if (!this.treewalker)
|
|
return [null, null];
|
|
let e = null, t = null;
|
|
for (this.treewalker.currentNode = this.treewalker.root; this.treewalker.nextNode(); ) {
|
|
const i = this.treewalker.currentNode;
|
|
B(i) && (e || (e = i), t = i);
|
|
}
|
|
return [e, t];
|
|
}
|
|
};
|
|
o([
|
|
u({ type: Boolean })
|
|
], s.prototype, "open", null);
|
|
o([
|
|
u({ type: Boolean })
|
|
], s.prototype, "quick", void 0);
|
|
o([
|
|
u({ attribute: !1 })
|
|
], s.prototype, "returnValue", void 0);
|
|
o([
|
|
u()
|
|
], s.prototype, "type", void 0);
|
|
o([
|
|
u({ type: Boolean, attribute: "no-focus-trap" })
|
|
], s.prototype, "noFocusTrap", void 0);
|
|
o([
|
|
l("dialog")
|
|
], s.prototype, "dialog", void 0);
|
|
o([
|
|
l(".scrim")
|
|
], s.prototype, "scrim", void 0);
|
|
o([
|
|
l(".container")
|
|
], s.prototype, "container", void 0);
|
|
o([
|
|
l(".headline")
|
|
], s.prototype, "headline", void 0);
|
|
o([
|
|
l(".content")
|
|
], s.prototype, "content", void 0);
|
|
o([
|
|
l(".actions")
|
|
], s.prototype, "actions", void 0);
|
|
o([
|
|
g()
|
|
], s.prototype, "isAtScrollTop", void 0);
|
|
o([
|
|
g()
|
|
], s.prototype, "isAtScrollBottom", void 0);
|
|
o([
|
|
l(".scroller")
|
|
], s.prototype, "scroller", void 0);
|
|
o([
|
|
l(".top.anchor")
|
|
], s.prototype, "topAnchor", void 0);
|
|
o([
|
|
l(".bottom.anchor")
|
|
], s.prototype, "bottomAnchor", void 0);
|
|
o([
|
|
l(".focus-trap")
|
|
], s.prototype, "firstFocusTrap", void 0);
|
|
o([
|
|
g()
|
|
], s.prototype, "hasHeadline", void 0);
|
|
o([
|
|
g()
|
|
], s.prototype, "hasActions", void 0);
|
|
o([
|
|
g()
|
|
], s.prototype, "hasIcon", void 0);
|
|
function B(n) {
|
|
var r;
|
|
const e = ":is(button,input,select,textarea,object,:is(a,area)[href],[tabindex],[contenteditable=true])", t = ":not(:disabled,[disabled])";
|
|
return n.matches(e + t + ':not([tabindex^="-"])') ? !0 : !n.localName.includes("-") || !n.matches(t) ? !1 : ((r = n.shadowRoot) == null ? void 0 : r.delegatesFocus) ?? !1;
|
|
}
|
|
/**
|
|
* @license
|
|
* Copyright 2024 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
const R = N`:host{border-start-start-radius:var(--md-dialog-container-shape-start-start, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-start-end-radius:var(--md-dialog-container-shape-start-end, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-end-end-radius:var(--md-dialog-container-shape-end-end, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-end-start-radius:var(--md-dialog-container-shape-end-start, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));display:contents;margin:auto;max-height:min(560px,100% - 48px);max-width:min(560px,100% - 48px);min-height:140px;min-width:280px;position:fixed;height:fit-content;width:fit-content}dialog{background:rgba(0,0,0,0);border:none;border-radius:inherit;flex-direction:column;height:inherit;margin:inherit;max-height:inherit;max-width:inherit;min-height:inherit;min-width:inherit;outline:none;overflow:visible;padding:0;width:inherit}dialog[open]{display:flex}::backdrop{background:none}.scrim{background:var(--md-sys-color-scrim, #000);display:none;inset:0;opacity:32%;pointer-events:none;position:fixed;z-index:1}:host([open]) .scrim{display:flex}h2{all:unset;align-self:stretch}.headline{align-items:center;color:var(--md-dialog-headline-color, var(--md-sys-color-on-surface, #1d1b20));display:flex;flex-direction:column;font-family:var(--md-dialog-headline-font, var(--md-sys-typescale-headline-small-font, var(--md-ref-typeface-brand, Roboto)));font-size:var(--md-dialog-headline-size, var(--md-sys-typescale-headline-small-size, 1.5rem));line-height:var(--md-dialog-headline-line-height, var(--md-sys-typescale-headline-small-line-height, 2rem));font-weight:var(--md-dialog-headline-weight, var(--md-sys-typescale-headline-small-weight, var(--md-ref-typeface-weight-regular, 400)));position:relative}slot[name=headline]::slotted(*){align-items:center;align-self:stretch;box-sizing:border-box;display:flex;gap:8px;padding:24px 24px 0}.icon{display:flex}slot[name=icon]::slotted(*){color:var(--md-dialog-icon-color, var(--md-sys-color-secondary, #625b71));fill:currentColor;font-size:var(--md-dialog-icon-size, 24px);margin-top:24px;height:var(--md-dialog-icon-size, 24px);width:var(--md-dialog-icon-size, 24px)}.has-icon slot[name=headline]::slotted(*){justify-content:center;padding-top:16px}.scrollable slot[name=headline]::slotted(*){padding-bottom:16px}.scrollable.has-headline slot[name=content]::slotted(*){padding-top:8px}.container{border-radius:inherit;display:flex;flex-direction:column;flex-grow:1;overflow:hidden;position:relative;transform-origin:top}.container::before{background:var(--md-dialog-container-color, var(--md-sys-color-surface-container-high, #ece6f0));border-radius:inherit;content:"";inset:0;position:absolute}.scroller{display:flex;flex:1;flex-direction:column;overflow:hidden;z-index:1}.scrollable .scroller{overflow-y:scroll}.content{color:var(--md-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant, #49454f));font-family:var(--md-dialog-supporting-text-font, var(--md-sys-typescale-body-medium-font, var(--md-ref-typeface-plain, Roboto)));font-size:var(--md-dialog-supporting-text-size, var(--md-sys-typescale-body-medium-size, 0.875rem));line-height:var(--md-dialog-supporting-text-line-height, var(--md-sys-typescale-body-medium-line-height, 1.25rem));flex:1;font-weight:var(--md-dialog-supporting-text-weight, var(--md-sys-typescale-body-medium-weight, var(--md-ref-typeface-weight-regular, 400)));height:min-content;position:relative}slot[name=content]::slotted(*){box-sizing:border-box;padding:24px}.anchor{position:absolute}.top.anchor{top:0}.bottom.anchor{bottom:0}.actions{position:relative}slot[name=actions]::slotted(*){box-sizing:border-box;display:flex;gap:8px;justify-content:flex-end;padding:16px 24px 24px}.has-actions slot[name=content]::slotted(*){padding-bottom:8px}md-divider{display:none;position:absolute}.has-headline.show-top-divider .headline md-divider,.has-actions.show-bottom-divider .actions md-divider{display:flex}.headline md-divider{bottom:0}.actions md-divider{top:0}@media(forced-colors: active){dialog{outline:2px solid WindowText}}
|
|
`;
|
|
/**
|
|
* @license
|
|
* Copyright 2023 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
let x = class extends s {
|
|
};
|
|
x.styles = [R];
|
|
x = o([
|
|
z("md-dialog")
|
|
], x);
|
|
const q = P({
|
|
react: S,
|
|
tagName: "md-dialog",
|
|
elementClass: x,
|
|
events: {
|
|
onClose: "close",
|
|
onShow: "show",
|
|
onOpen: "open",
|
|
onOpened: "opened",
|
|
onClosed: "closed",
|
|
onCancel: "cancel"
|
|
}
|
|
}), te = (n) => {
|
|
const { children: e, quick: t, returnValue: i, noFocusTrap: a, open: r, fullScreen: d, style: c, className: p, id: f, onClose: v, onShow: m, onOpen: w, onOpened: A, onClosed: E, onCancel: y } = n;
|
|
return /* @__PURE__ */ C(
|
|
q,
|
|
{
|
|
quick: t,
|
|
returnValue: i,
|
|
noFocusTrap: a,
|
|
open: r,
|
|
style: {
|
|
...c,
|
|
...d ? {
|
|
width: "100vw",
|
|
height: "100vh",
|
|
maxWidth: "100vw",
|
|
maxHeight: "100vh"
|
|
} : {}
|
|
},
|
|
className: p,
|
|
id: f,
|
|
onClose: v,
|
|
onShow: m,
|
|
onOpen: w,
|
|
onOpened: A,
|
|
onClosed: E,
|
|
onCancel: y,
|
|
children: e
|
|
}
|
|
);
|
|
}, ie = (n) => /* @__PURE__ */ C("div", { slot: "headline", ...n, children: n.children }), oe = (n) => /* @__PURE__ */ C("div", { slot: "content", ...n, children: n.children }), se = (n) => /* @__PURE__ */ C("div", { slot: "actions", ...n, children: n.children });
|
|
export {
|
|
te as Dialog,
|
|
se as DialogActions,
|
|
oe as DialogContent,
|
|
ie as DialogTitle
|
|
};
|