@nocobase/plugin-verification 2.1.0-beta.9 → 2.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.
- package/client-v2.d.ts +2 -0
- package/client-v2.js +1 -0
- package/dist/client/152.480ad14fee48be71.js +10 -0
- package/dist/client/478.bb62159e1d524faa.js +10 -0
- package/dist/client/index.js +1 -1
- package/dist/client-v2/190.596918843af85477.js +10 -0
- package/dist/client-v2/290.a651bc7c42fc98bc.js +10 -0
- package/dist/client-v2/548.eb3ed70d62d68d60.js +10 -0
- package/dist/client-v2/81.b8599d97bf4ca2a8.js +10 -0
- package/dist/client-v2/934.a3c0fa32883528e4.js +10 -0
- package/dist/client-v2/973.8a85e3793371482b.js +10 -0
- package/dist/client-v2/components/VerificationCode.d.ts +49 -0
- package/dist/client-v2/components/VerifierSelect.d.ts +45 -0
- package/dist/client-v2/index.d.ts +19 -0
- package/dist/client-v2/index.js +10 -0
- package/dist/client-v2/locale.d.ts +17 -0
- package/dist/client-v2/otp-sms-provider-manager.d.ts +35 -0
- package/dist/client-v2/otp-verification/sms/AdminSettingsForm.d.ts +21 -0
- package/dist/client-v2/otp-verification/sms/BindForm.d.ts +18 -0
- package/dist/client-v2/otp-verification/sms/VerificationForm.d.ts +18 -0
- package/dist/client-v2/otp-verification/sms/index.d.ts +25 -0
- package/dist/client-v2/otp-verification/sms/providers/AliyunSettings.d.ts +17 -0
- package/dist/client-v2/otp-verification/sms/providers/TencentSettings.d.ts +17 -0
- package/dist/client-v2/pages/VerifiersPage.d.ts +61 -0
- package/dist/client-v2/plugin.d.ts +25 -0
- package/dist/client-v2/user-center/MyVerifiers.d.ts +19 -0
- package/dist/client-v2/user-center/VerificationUserCenterItemModel.d.ts +29 -0
- package/dist/client-v2/verification-manager.d.ts +49 -0
- package/dist/externalVersion.js +10 -7
- package/dist/node_modules/@alicloud/dysmsapi20170525/dist/client.js +2 -2
- package/dist/node_modules/@alicloud/{openapi-client → dysmsapi20170525}/node_modules/@alicloud/openapi-util/dist/client.js +4 -28
- package/dist/node_modules/@alicloud/{openapi-client → dysmsapi20170525}/node_modules/@alicloud/openapi-util/package.json +1 -1
- package/dist/node_modules/@alicloud/{openapi-client → dysmsapi20170525}/node_modules/@alicloud/openapi-util/src/client.ts +5 -25
- package/dist/node_modules/@alicloud/dysmsapi20170525/package.json +1 -1
- package/dist/node_modules/@alicloud/openapi-client/dist/client.js +2 -2
- package/dist/node_modules/@alicloud/openapi-client/package.json +1 -1
- package/dist/node_modules/@alicloud/tea-util/dist/client.js +1 -1
- package/dist/node_modules/@alicloud/tea-util/package.json +1 -1
- package/dist/node_modules/tencentcloud-sdk-nodejs-sms/package.json +1 -1
- package/dist/node_modules/tencentcloud-sdk-nodejs-sms/tencentcloud/index.js +5 -5
- package/dist/server/collections/otp-records.js +1 -0
- package/dist/server/collections/users-verifiers.js +1 -0
- package/dist/server/collections/verifiers.js +2 -1
- package/package.json +4 -2
- package/dist/client/0c72f307d843dc6a.js +0 -10
- package/dist/client/20e6e5fa4c397f95.js +0 -10
- /package/dist/node_modules/@alicloud/{openapi-client → dysmsapi20170525}/node_modules/@alicloud/openapi-util/dist/client.d.ts +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
/**
|
|
11
|
+
* Admin settings form for an SMS-OTP verifier:
|
|
12
|
+
* 1. `options.provider` selects which configured SMS provider (Aliyun /
|
|
13
|
+
* Tencent / …) sends the OTP. The list is the server resource
|
|
14
|
+
* `smsOTPProviders:list`.
|
|
15
|
+
* 2. `options.settings.*` is the provider-specific configuration form,
|
|
16
|
+
* looked up from the plugin's `smsOTPProviderManager` at runtime so
|
|
17
|
+
* third-party providers contributed via `registerProvider()` slot in
|
|
18
|
+
* automatically.
|
|
19
|
+
*/
|
|
20
|
+
export declare function AdminSettingsForm(): React.JSX.Element;
|
|
21
|
+
export default AdminSettingsForm;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import type { BindFormProps } from '../../verification-manager';
|
|
11
|
+
/**
|
|
12
|
+
* SMS-OTP bind form. Same shape as `VerificationForm` minus the bound
|
|
13
|
+
* publicInfo path — when binding, the user is always typing in a new
|
|
14
|
+
* phone number. Hosted inside the parent `<Form>` so `uuid` / `code`
|
|
15
|
+
* land on the parent's `form.values`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function BindForm(props: BindFormProps): React.JSX.Element;
|
|
18
|
+
export default BindForm;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import type { VerificationFormProps } from '../../verification-manager';
|
|
11
|
+
/**
|
|
12
|
+
* SMS-OTP verify form: phone number (read-only when bound) + verification
|
|
13
|
+
* code field paired with a "send code" button. Hosted inside a parent
|
|
14
|
+
* `<Form>` — antd Form.Item paths land on `uuid` (phone) and `code`,
|
|
15
|
+
* matching the v1 schema so server-side handlers are unchanged.
|
|
16
|
+
*/
|
|
17
|
+
export declare function VerificationForm(props: VerificationFormProps): React.JSX.Element;
|
|
18
|
+
export default VerificationForm;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
export declare const smsOTPVerificationOptions: {
|
|
10
|
+
components: {
|
|
11
|
+
VerificationFormLoader: () => Promise<typeof import("./VerificationForm")>;
|
|
12
|
+
AdminSettingsFormLoader: () => Promise<typeof import("./AdminSettingsForm")>;
|
|
13
|
+
BindFormLoader: () => Promise<typeof import("./BindForm")>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare const smsAliyunProviderOptions: {
|
|
17
|
+
components: {
|
|
18
|
+
AdminSettingsFormLoader: () => Promise<typeof import("./providers/AliyunSettings")>;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare const smsTencentProviderOptions: {
|
|
22
|
+
components: {
|
|
23
|
+
AdminSettingsFormLoader: () => Promise<typeof import("./providers/TencentSettings")>;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
/**
|
|
11
|
+
* Aliyun SMS provider settings. Field names match the v1 schema 1:1, so
|
|
12
|
+
* the persisted shape on the server is unchanged. Each value can be a
|
|
13
|
+
* literal credential or an `{{ $env.X }}` reference; secret fields use
|
|
14
|
+
* `EnvVariableInput`'s `password` mode to mask non-variable values.
|
|
15
|
+
*/
|
|
16
|
+
export declare function AliyunSettings(): React.JSX.Element;
|
|
17
|
+
export default AliyunSettings;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
/**
|
|
11
|
+
* Tencent SMS provider settings. Mirror of v1 schema; persisted payload
|
|
12
|
+
* keys are unchanged. Secret credentials use `EnvVariableInput`'s
|
|
13
|
+
* `password` mode so literal values are masked but `{{ $env.X }}`
|
|
14
|
+
* references stay editable through the picker.
|
|
15
|
+
*/
|
|
16
|
+
export declare function TencentSettings(): React.JSX.Element;
|
|
17
|
+
export default TencentSettings;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
export type VerifierOptions = Record<string, unknown>;
|
|
11
|
+
export type VerifierRecord = {
|
|
12
|
+
name?: string;
|
|
13
|
+
title?: string | null;
|
|
14
|
+
description?: string | null;
|
|
15
|
+
verificationType?: string;
|
|
16
|
+
options?: VerifierOptions;
|
|
17
|
+
};
|
|
18
|
+
export type VerifierFormValues = {
|
|
19
|
+
name?: string;
|
|
20
|
+
title?: string | null;
|
|
21
|
+
description?: string | null;
|
|
22
|
+
verificationType?: string;
|
|
23
|
+
options?: VerifierOptions;
|
|
24
|
+
};
|
|
25
|
+
export declare function recursiveTrim<T>(value: T): T;
|
|
26
|
+
/**
|
|
27
|
+
* Submit pipeline for the create/edit verifier drawer.
|
|
28
|
+
*
|
|
29
|
+
* Extracted from the React component so the request layer can be tested
|
|
30
|
+
* directly without spinning up the full FlowEngine + viewer stack.
|
|
31
|
+
*
|
|
32
|
+
* The fallthrough `else` is deliberate — it converts what used to be a
|
|
33
|
+
* silent no-op (when `record.name` was undefined because we read the
|
|
34
|
+
* wrong primary key) into a loud error. The `verifiers` collection uses
|
|
35
|
+
* `name` as its primary key (`autoGenId: false`), so `filterByTk` must
|
|
36
|
+
* be the name string.
|
|
37
|
+
*/
|
|
38
|
+
export type VerifierResource = {
|
|
39
|
+
create(params: {
|
|
40
|
+
values: VerifierFormValues;
|
|
41
|
+
}): Promise<unknown>;
|
|
42
|
+
update(params: {
|
|
43
|
+
filterByTk: string;
|
|
44
|
+
values: VerifierFormValues;
|
|
45
|
+
}): Promise<unknown>;
|
|
46
|
+
};
|
|
47
|
+
export declare function submitVerifierForm(args: {
|
|
48
|
+
raw: VerifierFormValues;
|
|
49
|
+
mode: 'create' | 'edit';
|
|
50
|
+
record?: VerifierRecord;
|
|
51
|
+
resource: VerifierResource;
|
|
52
|
+
onSubmitted: () => void;
|
|
53
|
+
}): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Admin settings page for the Verification plugin. Lists all configured
|
|
56
|
+
* verifiers with create / edit / delete + bulk delete. Per-type fields
|
|
57
|
+
* are injected from `verificationManager` registered via the plugin
|
|
58
|
+
* registry so third-party verifier types (TOTP, future biometric, …)
|
|
59
|
+
* plug in without touching this page.
|
|
60
|
+
*/
|
|
61
|
+
export default function VerifiersPage(): React.JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Plugin } from '@nocobase/client-v2';
|
|
10
|
+
import { SMSOTPProviderManager } from './otp-sms-provider-manager';
|
|
11
|
+
import { VerificationManager } from './verification-manager';
|
|
12
|
+
/**
|
|
13
|
+
* v2 entry for the Verification plugin. Mirrors the v1 surface (`verificationManager` and `smsOTPProviderManager` instances exposed to downstream plugins) but plugs into the v2 lifecycle:
|
|
14
|
+
*
|
|
15
|
+
* - `pluginSettingsManager.addMenuItem` / `addPageTabItem` register the admin settings page with a lazy `componentLoader`.
|
|
16
|
+
* - `flowEngine.registerModels` contributes the User Center entry.
|
|
17
|
+
* - The legacy `src/client/` entry is intentionally left in place so downstream v1-only plugins (TOTP authenticator, 2FA pro plugin) keep working until they migrate independently.
|
|
18
|
+
*/
|
|
19
|
+
export declare class PluginVerificationClientV2 extends Plugin {
|
|
20
|
+
verificationManager: VerificationManager;
|
|
21
|
+
smsOTPProviderManager: SMSOTPProviderManager;
|
|
22
|
+
load(): Promise<void>;
|
|
23
|
+
private registerSettingsPages;
|
|
24
|
+
}
|
|
25
|
+
export default PluginVerificationClientV2;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
/**
|
|
11
|
+
* Drawer content for the User Center's "Verification" entry. Lists
|
|
12
|
+
* every verifier the current user can bind/unbind, with a Configured /
|
|
13
|
+
* Not configured tag and a per-row action. Bind opens a type-specific
|
|
14
|
+
* sub-drawer; Unbind opens a Tabs-based confirmation drawer that
|
|
15
|
+
* authenticates the user with any other bound verifier before removing
|
|
16
|
+
* the target.
|
|
17
|
+
*/
|
|
18
|
+
export declare function MyVerifiers(): React.JSX.Element;
|
|
19
|
+
export default MyVerifiers;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { UserCenterActionItemModel } from '@nocobase/client-v2';
|
|
10
|
+
/**
|
|
11
|
+
* User Center entry that opens the "My verifiers" drawer. Section is
|
|
12
|
+
* `profile` so it sits next to language / theme controls. Sort is
|
|
13
|
+
* tightened to 150 to match v1's ordering, where Verification lived
|
|
14
|
+
* between Profile (100) and Theme (200).
|
|
15
|
+
*
|
|
16
|
+
* The base `UserCenterTextItemView` renders `getLabelNode()`, which by
|
|
17
|
+
* default routes through `this.context.t(label)` with no namespace —
|
|
18
|
+
* that would never resolve the verification-namespaced key. Override
|
|
19
|
+
* the node directly so the verification i18n namespace is consulted.
|
|
20
|
+
*/
|
|
21
|
+
export declare class VerificationUserCenterItemModel extends UserCenterActionItemModel {
|
|
22
|
+
static itemId: string;
|
|
23
|
+
section: "profile";
|
|
24
|
+
sort: number;
|
|
25
|
+
label: string;
|
|
26
|
+
getLabelNode(): string;
|
|
27
|
+
onClick(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export default VerificationUserCenterItemModel;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import type { ComponentType } from 'react';
|
|
10
|
+
export type VerificationFormProps = {
|
|
11
|
+
verifier: string;
|
|
12
|
+
actionType: string;
|
|
13
|
+
boundInfo?: {
|
|
14
|
+
bound?: boolean;
|
|
15
|
+
publicInfo?: any;
|
|
16
|
+
};
|
|
17
|
+
isLogged?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type BindFormProps = {
|
|
20
|
+
verifier: string;
|
|
21
|
+
actionType: string;
|
|
22
|
+
isLogged?: boolean;
|
|
23
|
+
};
|
|
24
|
+
type LoaderOf<P = Record<string, never>> = () => Promise<{
|
|
25
|
+
default: ComponentType<P>;
|
|
26
|
+
}>;
|
|
27
|
+
export type VerificationTypeOptions = {
|
|
28
|
+
/**
|
|
29
|
+
* Async loaders for the type-specific forms. The manager stores loaders
|
|
30
|
+
* rather than direct component references so each verifier type
|
|
31
|
+
* contributes its own webpack chunk and is only fetched when a verifier
|
|
32
|
+
* of that type is actually shown.
|
|
33
|
+
*
|
|
34
|
+
* Consumers wrap each loader with `React.lazy` (cached via `useMemo` or
|
|
35
|
+
* a per-type cache to avoid re-creating the lazy wrapper) and render it
|
|
36
|
+
* under `<Suspense>`.
|
|
37
|
+
*/
|
|
38
|
+
components: {
|
|
39
|
+
AdminSettingsFormLoader?: LoaderOf;
|
|
40
|
+
VerificationFormLoader?: LoaderOf<VerificationFormProps>;
|
|
41
|
+
BindFormLoader?: LoaderOf<BindFormProps>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare class VerificationManager {
|
|
45
|
+
verifications: any;
|
|
46
|
+
registerVerificationType(type: string, options: VerificationTypeOptions): void;
|
|
47
|
+
getVerification(type: string): any;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
package/dist/externalVersion.js
CHANGED
|
@@ -8,21 +8,24 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
|
-
"@nocobase/client": "2.1.0
|
|
11
|
+
"@nocobase/client": "2.1.0",
|
|
12
12
|
"react": "18.2.0",
|
|
13
13
|
"antd": "5.24.2",
|
|
14
14
|
"@formily/shared": "2.3.7",
|
|
15
15
|
"@formily/react": "2.3.7",
|
|
16
16
|
"@formily/core": "2.3.7",
|
|
17
|
-
"@nocobase/
|
|
18
|
-
"@nocobase/utils": "2.1.0-beta.9",
|
|
19
|
-
"@nocobase/cache": "2.1.0-beta.9",
|
|
20
|
-
"@nocobase/actions": "2.1.0-beta.9",
|
|
21
|
-
"@nocobase/database": "2.1.0-beta.9",
|
|
17
|
+
"@nocobase/flow-engine": "2.1.0",
|
|
22
18
|
"react-i18next": "11.18.6",
|
|
19
|
+
"@nocobase/utils": "2.1.0",
|
|
20
|
+
"@nocobase/client-v2": "2.1.0",
|
|
21
|
+
"@nocobase/server": "2.1.0",
|
|
22
|
+
"@nocobase/cache": "2.1.0",
|
|
23
|
+
"@nocobase/actions": "2.1.0",
|
|
24
|
+
"@nocobase/database": "2.1.0",
|
|
23
25
|
"react-router-dom": "6.30.1",
|
|
24
26
|
"@formily/antd-v5": "1.2.3",
|
|
25
27
|
"@ant-design/icons": "5.6.1",
|
|
26
|
-
"
|
|
28
|
+
"ahooks": "3.7.8",
|
|
29
|
+
"lodash": "4.18.1",
|
|
27
30
|
"dayjs": "1.11.13"
|
|
28
31
|
};
|