@storybook/core-webpack 9.2.0-alpha.3 → 10.0.0-beta.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/README.md +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +173 -8
- package/package.json +7 -17
- package/dist/index.mjs +0 -49
package/README.md
CHANGED
|
@@ -7,3 +7,5 @@ This is a lot of code extracted for convenience, not because it made sense.
|
|
|
7
7
|
Supporting multiple version of webpack and this duplicating a large portion of code that was never meant to be generic caused this.
|
|
8
8
|
|
|
9
9
|
At some point we'll refactor this, it's likely a lot of this code is dead or barely used.
|
|
10
|
+
|
|
11
|
+
Learn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ type StorybookConfig<TWebpackConfiguration = WebpackConfiguration> = StorybookCo
|
|
|
31
31
|
webpackFinal?: (config: TWebpackConfiguration, options: Options) => TWebpackConfiguration | Promise<TWebpackConfiguration>;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
declare const loadCustomWebpackConfig: (configDir: string) => any
|
|
34
|
+
declare const loadCustomWebpackConfig: (configDir: string) => Promise<any>;
|
|
35
35
|
|
|
36
36
|
declare const checkWebpackVersion: (webpack: {
|
|
37
37
|
version?: string;
|
|
@@ -52,4 +52,4 @@ declare const toRequireContext: (specifier: NormalizedStoriesSpecifier) => {
|
|
|
52
52
|
};
|
|
53
53
|
declare const toRequireContextString: (specifier: NormalizedStoriesSpecifier) => string;
|
|
54
54
|
|
|
55
|
-
export { BuilderOptions, ModuleConfig, ResolveConfig, RulesConfig, StorybookConfig, WebpackConfiguration, checkWebpackVersion, loadCustomWebpackConfig, mergeConfigs, toImportFn, toImportFnPart, toRequireContext, toRequireContextString, webpackIncludeRegexp };
|
|
55
|
+
export { type BuilderOptions, type ModuleConfig, type ResolveConfig, type RulesConfig, type StorybookConfig, type WebpackConfiguration, checkWebpackVersion, loadCustomWebpackConfig, mergeConfigs, toImportFn, toImportFnPart, toRequireContext, toRequireContextString, webpackIncludeRegexp };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
import CJS_COMPAT_NODE_URL_9aa7rkxznnr from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_9aa7rkxznnr from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_9aa7rkxznnr from "node:module";
|
|
4
|
+
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_9aa7rkxznnr.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_9aa7rkxznnr.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_9aa7rkxznnr.createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
// ------------------------------------------------------------
|
|
10
|
+
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
|
|
11
|
+
// ------------------------------------------------------------
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
14
|
+
|
|
15
|
+
// src/load-custom-webpack-config.ts
|
|
16
|
+
import { resolve } from "node:path";
|
|
17
|
+
import { serverRequire } from "storybook/internal/common";
|
|
18
|
+
var webpackConfigs = ["webpack.config", "webpackfile"];
|
|
19
|
+
var loadCustomWebpackConfig = /* @__PURE__ */ __name(async (configDir) => serverRequire(webpackConfigs.map((configName) => resolve(configDir, configName))), "loadCustomWebpackConfig");
|
|
20
|
+
|
|
21
|
+
// src/check-webpack-version.ts
|
|
22
|
+
import { logger } from "storybook/internal/node-logger";
|
|
23
|
+
import { dedent } from "ts-dedent";
|
|
24
|
+
var checkWebpackVersion = /* @__PURE__ */ __name((webpack, specifier, caption) => {
|
|
25
|
+
if (!webpack.version) {
|
|
26
|
+
logger.info("Skipping webpack version check, no version available");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (webpack.version !== specifier) {
|
|
30
|
+
logger.warn(dedent`
|
|
2
31
|
Unexpected webpack version in ${caption}:
|
|
3
32
|
- Received '${webpack.version}'
|
|
4
33
|
- Expected '${specifier}'
|
|
@@ -6,13 +35,113 @@
|
|
|
6
35
|
If you're using Webpack 5 in SB6.2 and upgrading, consider: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack-5-manager-build
|
|
7
36
|
|
|
8
37
|
For more info about Webpack 5 support: https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324#troubleshooting
|
|
9
|
-
`)
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
}, "checkWebpackVersion");
|
|
41
|
+
|
|
42
|
+
// src/merge-webpack-config.ts
|
|
43
|
+
function mergePluginsField(defaultPlugins = [], customPlugins = []) {
|
|
44
|
+
return [...defaultPlugins, ...customPlugins];
|
|
45
|
+
}
|
|
46
|
+
__name(mergePluginsField, "mergePluginsField");
|
|
47
|
+
function mergeRulesField(defaultRules = [], customRules = []) {
|
|
48
|
+
return [...defaultRules, ...customRules];
|
|
49
|
+
}
|
|
50
|
+
__name(mergeRulesField, "mergeRulesField");
|
|
51
|
+
function mergeExtensionsField({ extensions: defaultExtensions = [] }, { extensions: customExtensions = [] }) {
|
|
52
|
+
return [...defaultExtensions, ...customExtensions];
|
|
53
|
+
}
|
|
54
|
+
__name(mergeExtensionsField, "mergeExtensionsField");
|
|
55
|
+
function mergeAliasField({ alias: defaultAlias = {} }, { alias: customAlias = {} }) {
|
|
56
|
+
return {
|
|
57
|
+
...defaultAlias,
|
|
58
|
+
...customAlias
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
__name(mergeAliasField, "mergeAliasField");
|
|
62
|
+
function mergeModuleField(a, b) {
|
|
63
|
+
return {
|
|
64
|
+
...a,
|
|
65
|
+
...b,
|
|
66
|
+
rules: mergeRulesField(a.rules || [], b.rules || [])
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
__name(mergeModuleField, "mergeModuleField");
|
|
70
|
+
function mergeResolveField({ resolve: defaultResolve = {} }, { resolve: customResolve = {} }) {
|
|
71
|
+
return {
|
|
72
|
+
...defaultResolve,
|
|
73
|
+
...customResolve,
|
|
74
|
+
alias: mergeAliasField(defaultResolve, customResolve),
|
|
75
|
+
extensions: mergeExtensionsField(defaultResolve, customResolve)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
__name(mergeResolveField, "mergeResolveField");
|
|
79
|
+
function mergeOptimizationField({ optimization: defaultOptimization = {} }, { optimization: customOptimization = {} }) {
|
|
80
|
+
return {
|
|
81
|
+
...defaultOptimization,
|
|
82
|
+
...customOptimization
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
__name(mergeOptimizationField, "mergeOptimizationField");
|
|
86
|
+
function mergeConfigs(config, customConfig) {
|
|
87
|
+
return {
|
|
88
|
+
// We'll always load our configurations after the custom config.
|
|
89
|
+
// So, we'll always load the stuff we need.
|
|
90
|
+
...customConfig,
|
|
91
|
+
...config,
|
|
92
|
+
devtool: customConfig.devtool || config.devtool,
|
|
93
|
+
plugins: mergePluginsField(config.plugins, customConfig.plugins),
|
|
94
|
+
module: mergeModuleField(config.module || {}, customConfig.module || {}),
|
|
95
|
+
resolve: mergeResolveField(config, customConfig),
|
|
96
|
+
optimization: mergeOptimizationField(config, customConfig)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
__name(mergeConfigs, "mergeConfigs");
|
|
100
|
+
|
|
101
|
+
// src/to-importFn.ts
|
|
102
|
+
import { globToRegexp } from "storybook/internal/common";
|
|
103
|
+
import { dedent as dedent2 } from "ts-dedent";
|
|
104
|
+
|
|
105
|
+
// src/importPipeline.ts
|
|
106
|
+
function importPipeline() {
|
|
107
|
+
let importGate = Promise.resolve();
|
|
108
|
+
return async (importFn) => {
|
|
109
|
+
await importGate;
|
|
110
|
+
const moduleExportsPromise = importFn();
|
|
111
|
+
importGate = importGate.then(async () => {
|
|
112
|
+
await moduleExportsPromise;
|
|
113
|
+
});
|
|
114
|
+
return moduleExportsPromise;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
__name(importPipeline, "importPipeline");
|
|
118
|
+
|
|
119
|
+
// src/to-importFn.ts
|
|
120
|
+
function adjustRegexToExcludeNodeModules(originalRegex) {
|
|
121
|
+
const originalRegexString = originalRegex.source;
|
|
122
|
+
const startsWithCaret = originalRegexString.startsWith("^");
|
|
123
|
+
const excludeNodeModulesPattern = startsWithCaret ? "(?!.*node_modules)" : "^(?!.*node_modules)";
|
|
124
|
+
const adjustedRegexString = startsWithCaret ? `^${excludeNodeModulesPattern}${originalRegexString.substring(1)}` : excludeNodeModulesPattern + originalRegexString;
|
|
125
|
+
return new RegExp(adjustedRegexString);
|
|
126
|
+
}
|
|
127
|
+
__name(adjustRegexToExcludeNodeModules, "adjustRegexToExcludeNodeModules");
|
|
128
|
+
function webpackIncludeRegexp(specifier) {
|
|
129
|
+
const { directory, files } = specifier;
|
|
130
|
+
const directoryWithoutLeadingDots = directory.replace(/^(\.+\/)+/, "/");
|
|
131
|
+
const webpackIncludeGlob = [".", ".."].includes(directory) ? files : `${directoryWithoutLeadingDots}/${files}`;
|
|
132
|
+
const webpackIncludeRegexpWithCaret = webpackIncludeGlob.includes("node_modules") ? globToRegexp(webpackIncludeGlob) : adjustRegexToExcludeNodeModules(globToRegexp(webpackIncludeGlob));
|
|
133
|
+
return new RegExp(webpackIncludeRegexpWithCaret.source.replace(/^\^/, ""));
|
|
134
|
+
}
|
|
135
|
+
__name(webpackIncludeRegexp, "webpackIncludeRegexp");
|
|
136
|
+
function toImportFnPart(specifier) {
|
|
137
|
+
const { directory, importPathMatcher } = specifier;
|
|
138
|
+
return dedent2`
|
|
10
139
|
async (path) => {
|
|
11
140
|
if (!${importPathMatcher}.exec(path)) {
|
|
12
141
|
return;
|
|
13
142
|
}
|
|
14
143
|
|
|
15
|
-
const pathRemainder = path.substring(${directory.length+1});
|
|
144
|
+
const pathRemainder = path.substring(${directory.length + 1});
|
|
16
145
|
return import(
|
|
17
146
|
/* webpackChunkName: "[request]" */
|
|
18
147
|
/* webpackInclude: ${webpackIncludeRegexp(specifier)} */
|
|
@@ -20,15 +149,22 @@
|
|
|
20
149
|
);
|
|
21
150
|
}
|
|
22
151
|
|
|
23
|
-
|
|
152
|
+
`;
|
|
153
|
+
}
|
|
154
|
+
__name(toImportFnPart, "toImportFnPart");
|
|
155
|
+
function toImportFn(stories, { needPipelinedImport } = {}) {
|
|
156
|
+
let pipelinedImport = `const pipeline = (x) => x();`;
|
|
157
|
+
if (needPipelinedImport) {
|
|
158
|
+
pipelinedImport = `
|
|
24
159
|
const importPipeline = ${importPipeline};
|
|
25
160
|
const pipeline = importPipeline();
|
|
26
|
-
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
return dedent2`
|
|
27
164
|
${pipelinedImport}
|
|
28
165
|
|
|
29
166
|
const importers = [
|
|
30
|
-
${stories.map(toImportFnPart).join(
|
|
31
|
-
`)}
|
|
167
|
+
${stories.map(toImportFnPart).join(",\n")}
|
|
32
168
|
];
|
|
33
169
|
|
|
34
170
|
export async function importFn(path) {
|
|
@@ -39,4 +175,33 @@
|
|
|
39
175
|
}
|
|
40
176
|
}
|
|
41
177
|
}
|
|
42
|
-
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
__name(toImportFn, "toImportFn");
|
|
181
|
+
|
|
182
|
+
// src/to-require-context.ts
|
|
183
|
+
import { globToRegexp as globToRegexp2 } from "storybook/internal/common";
|
|
184
|
+
var toRequireContext = /* @__PURE__ */ __name((specifier) => {
|
|
185
|
+
const { directory, files } = specifier;
|
|
186
|
+
const match = globToRegexp2(`./${files}`);
|
|
187
|
+
return {
|
|
188
|
+
path: directory,
|
|
189
|
+
recursive: files.includes("**") || files.split("/").length > 1,
|
|
190
|
+
match
|
|
191
|
+
};
|
|
192
|
+
}, "toRequireContext");
|
|
193
|
+
var toRequireContextString = /* @__PURE__ */ __name((specifier) => {
|
|
194
|
+
const { path: p, recursive: r, match: m } = toRequireContext(specifier);
|
|
195
|
+
const result = `require.context('${p}', ${r}, ${m})`;
|
|
196
|
+
return result;
|
|
197
|
+
}, "toRequireContextString");
|
|
198
|
+
export {
|
|
199
|
+
checkWebpackVersion,
|
|
200
|
+
loadCustomWebpackConfig,
|
|
201
|
+
mergeConfigs,
|
|
202
|
+
toImportFn,
|
|
203
|
+
toImportFnPart,
|
|
204
|
+
toRequireContext,
|
|
205
|
+
toRequireContextString,
|
|
206
|
+
webpackIncludeRegexp
|
|
207
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/core-webpack",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0-beta.0",
|
|
4
4
|
"description": "Storybook framework-agnostic API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook"
|
|
@@ -19,18 +19,14 @@
|
|
|
19
19
|
"url": "https://opencollective.com/storybook"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
|
+
"type": "module",
|
|
22
23
|
"exports": {
|
|
23
24
|
".": {
|
|
24
25
|
"types": "./dist/index.d.ts",
|
|
25
|
-
"
|
|
26
|
-
"import": "./dist/index.mjs",
|
|
27
|
-
"require": "./dist/index.js"
|
|
26
|
+
"default": "./dist/index.js"
|
|
28
27
|
},
|
|
29
28
|
"./package.json": "./package.json"
|
|
30
29
|
},
|
|
31
|
-
"main": "dist/index.js",
|
|
32
|
-
"module": "dist/index.mjs",
|
|
33
|
-
"types": "dist/index.d.ts",
|
|
34
30
|
"files": [
|
|
35
31
|
"dist/**/*",
|
|
36
32
|
"templates/**/*",
|
|
@@ -40,8 +36,8 @@
|
|
|
40
36
|
"!src/**/*"
|
|
41
37
|
],
|
|
42
38
|
"scripts": {
|
|
43
|
-
"check": "jiti ../../../scripts/
|
|
44
|
-
"prep": "jiti ../../../scripts/
|
|
39
|
+
"check": "jiti ../../../scripts/check/check-package.ts",
|
|
40
|
+
"prep": "jiti ../../../scripts/build/build-package.ts"
|
|
45
41
|
},
|
|
46
42
|
"dependencies": {
|
|
47
43
|
"ts-dedent": "^2.0.0"
|
|
@@ -52,16 +48,10 @@
|
|
|
52
48
|
"webpack": "5"
|
|
53
49
|
},
|
|
54
50
|
"peerDependencies": {
|
|
55
|
-
"storybook": "^
|
|
51
|
+
"storybook": "^10.0.0-beta.0"
|
|
56
52
|
},
|
|
57
53
|
"publishConfig": {
|
|
58
54
|
"access": "public"
|
|
59
55
|
},
|
|
60
|
-
"
|
|
61
|
-
"entries": [
|
|
62
|
-
"./src/index.ts"
|
|
63
|
-
],
|
|
64
|
-
"platform": "node"
|
|
65
|
-
},
|
|
66
|
-
"gitHead": "ce6a1e4a8d5ad69c699021a0b183df89cfc7b684"
|
|
56
|
+
"gitHead": "a8e7fd8a655c69780bc20b9749d2699e45beae16"
|
|
67
57
|
}
|
package/dist/index.mjs
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { serverRequire, globToRegexp } from 'storybook/internal/common';
|
|
3
|
-
import { logger } from 'storybook/internal/node-logger';
|
|
4
|
-
import { dedent } from 'ts-dedent';
|
|
5
|
-
|
|
6
|
-
var webpackConfigs=["webpack.config","webpackfile"],loadCustomWebpackConfig=configDir=>serverRequire(webpackConfigs.map(configName=>resolve(configDir,configName)));var checkWebpackVersion=(webpack,specifier,caption)=>{if(!webpack.version){logger.info("Skipping webpack version check, no version available");return}webpack.version!==specifier&&logger.warn(dedent`
|
|
7
|
-
Unexpected webpack version in ${caption}:
|
|
8
|
-
- Received '${webpack.version}'
|
|
9
|
-
- Expected '${specifier}'
|
|
10
|
-
|
|
11
|
-
If you're using Webpack 5 in SB6.2 and upgrading, consider: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack-5-manager-build
|
|
12
|
-
|
|
13
|
-
For more info about Webpack 5 support: https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324#troubleshooting
|
|
14
|
-
`);};function mergePluginsField(defaultPlugins=[],customPlugins=[]){return [...defaultPlugins,...customPlugins]}function mergeRulesField(defaultRules=[],customRules=[]){return [...defaultRules,...customRules]}function mergeExtensionsField({extensions:defaultExtensions=[]},{extensions:customExtensions=[]}){return [...defaultExtensions,...customExtensions]}function mergeAliasField({alias:defaultAlias={}},{alias:customAlias={}}){return {...defaultAlias,...customAlias}}function mergeModuleField(a,b){return {...a,...b,rules:mergeRulesField(a.rules||[],b.rules||[])}}function mergeResolveField({resolve:defaultResolve={}},{resolve:customResolve={}}){return {...defaultResolve,...customResolve,alias:mergeAliasField(defaultResolve,customResolve),extensions:mergeExtensionsField(defaultResolve,customResolve)}}function mergeOptimizationField({optimization:defaultOptimization={}},{optimization:customOptimization={}}){return {...defaultOptimization,...customOptimization}}function mergeConfigs(config,customConfig){return {...customConfig,...config,devtool:customConfig.devtool||config.devtool,plugins:mergePluginsField(config.plugins,customConfig.plugins),module:mergeModuleField(config.module||{},customConfig.module||{}),resolve:mergeResolveField(config,customConfig),optimization:mergeOptimizationField(config,customConfig)}}function importPipeline(){let importGate=Promise.resolve();return async importFn=>{await importGate;let moduleExportsPromise=importFn();return importGate=importGate.then(async()=>{await moduleExportsPromise;}),moduleExportsPromise}}function adjustRegexToExcludeNodeModules(originalRegex){let originalRegexString=originalRegex.source,startsWithCaret=originalRegexString.startsWith("^"),excludeNodeModulesPattern=startsWithCaret?"(?!.*node_modules)":"^(?!.*node_modules)",adjustedRegexString=startsWithCaret?`^${excludeNodeModulesPattern}${originalRegexString.substring(1)}`:excludeNodeModulesPattern+originalRegexString;return new RegExp(adjustedRegexString)}function webpackIncludeRegexp(specifier){let{directory,files}=specifier,directoryWithoutLeadingDots=directory.replace(/^(\.+\/)+/,"/"),webpackIncludeGlob=[".",".."].includes(directory)?files:`${directoryWithoutLeadingDots}/${files}`,webpackIncludeRegexpWithCaret=webpackIncludeGlob.includes("node_modules")?globToRegexp(webpackIncludeGlob):adjustRegexToExcludeNodeModules(globToRegexp(webpackIncludeGlob));return new RegExp(webpackIncludeRegexpWithCaret.source.replace(/^\^/,""))}function toImportFnPart(specifier){let{directory,importPathMatcher}=specifier;return dedent`
|
|
15
|
-
async (path) => {
|
|
16
|
-
if (!${importPathMatcher}.exec(path)) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const pathRemainder = path.substring(${directory.length+1});
|
|
21
|
-
return import(
|
|
22
|
-
/* webpackChunkName: "[request]" */
|
|
23
|
-
/* webpackInclude: ${webpackIncludeRegexp(specifier)} */
|
|
24
|
-
'${directory}/' + pathRemainder
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
`}function toImportFn(stories,{needPipelinedImport}={}){let pipelinedImport="const pipeline = (x) => x();";return needPipelinedImport&&(pipelinedImport=`
|
|
29
|
-
const importPipeline = ${importPipeline};
|
|
30
|
-
const pipeline = importPipeline();
|
|
31
|
-
`),dedent`
|
|
32
|
-
${pipelinedImport}
|
|
33
|
-
|
|
34
|
-
const importers = [
|
|
35
|
-
${stories.map(toImportFnPart).join(`,
|
|
36
|
-
`)}
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
export async function importFn(path) {
|
|
40
|
-
for (let i = 0; i < importers.length; i++) {
|
|
41
|
-
const moduleExports = await pipeline(() => importers[i](path));
|
|
42
|
-
if (moduleExports) {
|
|
43
|
-
return moduleExports;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
`}var toRequireContext=specifier=>{let{directory,files}=specifier,match=globToRegexp(`./${files}`);return {path:directory,recursive:files.includes("**")||files.split("/").length>1,match}},toRequireContextString=specifier=>{let{path:p,recursive:r,match:m}=toRequireContext(specifier);return `require.context('${p}', ${r}, ${m})`};
|
|
48
|
-
|
|
49
|
-
export { checkWebpackVersion, loadCustomWebpackConfig, mergeConfigs, toImportFn, toImportFnPart, toRequireContext, toRequireContextString, webpackIncludeRegexp };
|