@eclipse-scout/cli 11.0.41 → 22.0.0-beta.5
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 +3 -3
- package/bin/scout-scripts.js +1 -3
- package/package.json +35 -35
- package/scripts/karma-defaults.js +15 -9
- package/scripts/post-build.js +0 -1
- package/scripts/webpack-defaults.js +121 -25
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a href="https://ci.eclipse.org/scout/view/Scout%20Nightly%20Jobs/job/scout-integration-
|
|
7
|
-
<a href="https://ci.eclipse.org/scout/view/Scout%20Nightly%20Jobs/job/scout-integration-
|
|
6
|
+
<a href="https://ci.eclipse.org/scout/view/Scout%20Nightly%20Jobs/job/scout-integration-22.0-RT-nightly_pipeline/" target="_blank" rel="noopener noreferrer"><img alt="Jenkins" src="https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fci.eclipse.org%2Fscout%2Fview%2FScout%2520Nightly%2520Jobs%2Fjob%2Fscout-integration-22.0-RT-nightly_pipeline%2F"></a>
|
|
7
|
+
<a href="https://ci.eclipse.org/scout/view/Scout%20Nightly%20Jobs/job/scout-integration-22.0-RT-nightly_pipeline/" target="_blank" rel="noopener noreferrer"><img alt="Jenkins tests" src="https://img.shields.io/jenkins/tests?compact_message&jobUrl=https%3A%2F%2Fci.eclipse.org%2Fscout%2Fview%2FScout%2520Nightly%2520Jobs%2Fjob%2Fscout-integration-22.0-RT-nightly_pipeline%2F"></a>
|
|
8
8
|
<a href="https://www.npmjs.com/package/@eclipse-scout/cli" target="_blank" rel="noopener noreferrer"><img alt="npm" src="https://img.shields.io/npm/dm/@eclipse-scout/cli"></a>
|
|
9
9
|
<a href="https://www.eclipse.org/legal/epl-v10.html" target="_blank" rel="noopener noreferrer"><img alt="NPM" src="https://img.shields.io/npm/l/@eclipse-scout/cli"></a>
|
|
10
10
|
<a href="https://www.npmjs.com/package/@eclipse-scout/cli" target="_blank" rel="noopener noreferrer"><img alt="npm (scoped)" src="https://img.shields.io/npm/v/@eclipse-scout/cli"></a>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
# Eclipse Scout - CLI
|
|
16
16
|
|
|
17
|
-
Command Line Interface for the [Eclipse Scout](https://www.
|
|
17
|
+
Command Line Interface for the [Eclipse Scout](https://www.npmjs.com/package/@eclipse-scout/core) framework.
|
|
18
18
|
|
|
19
19
|
## License
|
|
20
20
|
|
package/bin/scout-scripts.js
CHANGED
|
@@ -29,7 +29,7 @@ const path = require('path');
|
|
|
29
29
|
const webpackConfigFileName = './webpack.config.js';
|
|
30
30
|
const webpackCustomConfigFileName = './webpack.config.custom.js';
|
|
31
31
|
const webpackYargsOptions = {
|
|
32
|
-
boolean: ['progress', 'profile'
|
|
32
|
+
boolean: ['progress', 'profile'],
|
|
33
33
|
array: ['resDirArray', 'themes']
|
|
34
34
|
};
|
|
35
35
|
const karmaYargsOptions = prepareWebpackYargsOptionsForKarma();
|
|
@@ -154,8 +154,6 @@ function readWebpackConfig() {
|
|
|
154
154
|
|
|
155
155
|
function runWebpackWatch(args) {
|
|
156
156
|
const configFilePath = readWebpackConfig();
|
|
157
|
-
// Don't clean the dist folder in watch mode, may be overridden by command line argument
|
|
158
|
-
args = Object.assign({clean: false}, args);
|
|
159
157
|
const {compiler, statsConfig} = createWebpackCompiler(configFilePath, args);
|
|
160
158
|
compiler.watch({}, (err, stats) => logWebpack(err, stats, statsConfig));
|
|
161
159
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eclipse-scout/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "22.0.0-beta.5",
|
|
4
4
|
"description": "CLI for Eclipse Scout",
|
|
5
5
|
"author": "BSI Business Systems Integration AG",
|
|
6
6
|
"homepage": "https://www.eclipse.org/scout",
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"license": "EPL-1.0",
|
|
12
12
|
"engines": {
|
|
13
|
-
"node": ">=
|
|
14
|
-
"npm": ">=
|
|
15
|
-
"pnpm": ">=
|
|
13
|
+
"node": ">=16.13.0",
|
|
14
|
+
"npm": ">=8.1.0",
|
|
15
|
+
"pnpm": ">=6.22.2"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"scout",
|
|
@@ -27,48 +27,48 @@
|
|
|
27
27
|
"bin",
|
|
28
28
|
"scripts"
|
|
29
29
|
],
|
|
30
|
-
"scripts": {
|
|
31
|
-
"snapshot-cleanup": "releng-scripts snapshot-cleanup",
|
|
32
|
-
"snapshot-predependency": "releng-scripts snapshot-install-dependency",
|
|
33
|
-
"snapshot-postdependency": "releng-scripts snapshot-publish-dependency",
|
|
34
|
-
"release-predependency": "releng-scripts release-install-dependency",
|
|
35
|
-
"release-postdependency": "releng-scripts release-publish-dependency"
|
|
36
|
-
},
|
|
37
30
|
"dependencies": {
|
|
38
|
-
"@babel/cli": "7.
|
|
39
|
-
"@babel/core": "7.
|
|
40
|
-
"@babel/plugin-proposal-class-properties": "7.
|
|
41
|
-
"@babel/plugin-proposal-object-rest-spread": "7.
|
|
42
|
-
"@babel/plugin-transform-object-assign": "7.
|
|
43
|
-
"@babel/preset-env": "7.
|
|
44
|
-
"babel-loader": "8.
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"css-loader": "
|
|
48
|
-
"jasmine-core": "3.
|
|
31
|
+
"@babel/cli": "7.16.0",
|
|
32
|
+
"@babel/core": "7.16.5",
|
|
33
|
+
"@babel/plugin-proposal-class-properties": "7.16.5",
|
|
34
|
+
"@babel/plugin-proposal-object-rest-spread": "7.16.5",
|
|
35
|
+
"@babel/plugin-transform-object-assign": "7.16.5",
|
|
36
|
+
"@babel/preset-env": "7.16.5",
|
|
37
|
+
"babel-loader": "8.2.3",
|
|
38
|
+
"copy-webpack-plugin": "10.2.0",
|
|
39
|
+
"style-loader": "3.3.1",
|
|
40
|
+
"css-loader": "6.5.1",
|
|
41
|
+
"jasmine-core": "3.10.1",
|
|
49
42
|
"jasmine-jquery": "2.1.1",
|
|
50
|
-
"jquery": "3.
|
|
51
|
-
"karma": "
|
|
43
|
+
"jquery": "3.6.0",
|
|
44
|
+
"karma": "6.3.9",
|
|
52
45
|
"karma-chrome-launcher": "3.1.0",
|
|
53
46
|
"karma-jasmine": "4.0.1",
|
|
54
47
|
"karma-jasmine-ajax": "0.1.13",
|
|
55
48
|
"@metahub/karma-jasmine-jquery": "4.0.1",
|
|
56
|
-
"@eclipse-scout/karma-jasmine-scout": "
|
|
57
|
-
"karma-jasmine-html-reporter": "1.
|
|
49
|
+
"@eclipse-scout/karma-jasmine-scout": "22.0.0-beta.5",
|
|
50
|
+
"karma-jasmine-html-reporter": "1.7.0",
|
|
58
51
|
"karma-junit-reporter": "2.0.1",
|
|
59
|
-
"karma-webpack": "
|
|
60
|
-
"less": "
|
|
61
|
-
"less-loader": "
|
|
62
|
-
"mini-css-extract-plugin": "
|
|
63
|
-
"
|
|
64
|
-
"terser-webpack-plugin": "
|
|
65
|
-
"webpack": "
|
|
66
|
-
"yargs-parser": "
|
|
52
|
+
"karma-webpack": "5.0.0",
|
|
53
|
+
"less": "4.1.2",
|
|
54
|
+
"less-loader": "10.2.0",
|
|
55
|
+
"mini-css-extract-plugin": "2.4.5",
|
|
56
|
+
"css-minimizer-webpack-plugin": "3.3.0",
|
|
57
|
+
"terser-webpack-plugin": "5.3.0",
|
|
58
|
+
"webpack": "5.65.0",
|
|
59
|
+
"yargs-parser": "21.0.0"
|
|
67
60
|
},
|
|
68
61
|
"devDependencies": {
|
|
69
|
-
"@eclipse-scout/releng": "^
|
|
62
|
+
"@eclipse-scout/releng": "^22.0.0"
|
|
70
63
|
},
|
|
71
64
|
"bin": {
|
|
72
65
|
"scout-scripts": "./bin/scout-scripts.js"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"cleanup:snapshots": "releng-scripts cleanup:snapshots",
|
|
69
|
+
"version:snapshot:dependencies": "releng-scripts version:snapshot:dependencies",
|
|
70
|
+
"version:snapshot": "releng-scripts version:snapshot",
|
|
71
|
+
"version:release:dependencies": "releng-scripts version:release:dependencies",
|
|
72
|
+
"version:release": "releng-scripts version:release"
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c)
|
|
2
|
+
* Copyright (c) 2010-2021 BSI Business Systems Integration AG.
|
|
3
3
|
* All rights reserved. This program and the accompanying materials
|
|
4
4
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
5
5
|
* which accompanies this distribution, and is available at
|
|
@@ -27,6 +27,16 @@ module.exports = (config, specEntryPoint) => {
|
|
|
27
27
|
const webpackArgs = Object.assign({mode: scoutBuild.mode.development}, config.webpackArgs);
|
|
28
28
|
const webpackConfig = webpackConfigProvider(null, webpackArgs);
|
|
29
29
|
delete webpackConfig.entry;
|
|
30
|
+
if (webpackConfig.optimization) {
|
|
31
|
+
delete webpackConfig.optimization.splitChunks; // disable splitting for tests
|
|
32
|
+
}
|
|
33
|
+
if (webpackConfig.output) {
|
|
34
|
+
delete webpackConfig.output.filename;
|
|
35
|
+
}
|
|
36
|
+
if (webpackConfig.output && webpackConfig.output.path) {
|
|
37
|
+
fs.mkdirSync(webpackConfig.output.path, {recursive: true});
|
|
38
|
+
}
|
|
39
|
+
webpackConfig.watch = true;
|
|
30
40
|
|
|
31
41
|
const sourceMapPlugin = webpackConfig.plugins.find(plugin => plugin instanceof webpack.SourceMapDevToolPlugin);
|
|
32
42
|
if (sourceMapPlugin) {
|
|
@@ -41,14 +51,10 @@ module.exports = (config, specEntryPoint) => {
|
|
|
41
51
|
config.set({
|
|
42
52
|
browsers: ['Chrome'],
|
|
43
53
|
files: [
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
pattern: specIndex,
|
|
49
|
-
watched: false
|
|
50
|
-
}],
|
|
51
|
-
frameworks: ['jasmine-scout', 'jasmine-jquery', 'jasmine-ajax', 'jasmine'], /* order of the frameworks is relevant! */
|
|
54
|
+
{pattern: jquery, watched: false},
|
|
55
|
+
{pattern: specIndex, watched: false}
|
|
56
|
+
],
|
|
57
|
+
frameworks: ['webpack', 'jasmine-scout', 'jasmine-jquery', 'jasmine-ajax', 'jasmine'], /* order of the frameworks is relevant! */
|
|
52
58
|
// Reporter for "Jasmine Spec Runner" results in browser
|
|
53
59
|
// https://www.npmjs.com/package/karma-jasmine-html-reporter
|
|
54
60
|
reporters: ['kjhtml', 'junit'],
|
package/scripts/post-build.js
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* Contributors:
|
|
9
9
|
* BSI Business Systems Integration AG - initial API and implementation
|
|
10
10
|
*/
|
|
11
|
-
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
|
12
11
|
const CopyPlugin = require('copy-webpack-plugin');
|
|
13
12
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
14
13
|
const AfterEmitWebpackPlugin = require('./AfterEmitWebpackPlugin');
|
|
@@ -19,7 +18,6 @@ const webpack = require('webpack');
|
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* @param {string} args.mode development or production
|
|
22
|
-
* @param {boolean} args.clean true, to clean the dist folder before each build. Default is true.
|
|
23
21
|
* @param {boolean} args.progress true, to show build progress in percentage. Default is true.
|
|
24
22
|
* @param {boolean} args.profile true, to show timing information for each build step. Default is false.
|
|
25
23
|
* @param {[]} args.resDirArray an array containing directories which should be copied to dist/res
|
|
@@ -51,10 +49,50 @@ module.exports = (env, args) => {
|
|
|
51
49
|
// In production mode create external source maps without source code to map stack traces.
|
|
52
50
|
// Otherwise stack traces would point to the minified source code which makes it quite impossible to analyze productive issues.
|
|
53
51
|
devtool: devMode ? false : 'nosources-source-map',
|
|
52
|
+
resolve: {
|
|
53
|
+
|
|
54
|
+
// no automatic polyfills. clients must add the desired polyfills themselves.
|
|
55
|
+
fallback: {
|
|
56
|
+
assert: false,
|
|
57
|
+
buffer: false,
|
|
58
|
+
console: false,
|
|
59
|
+
constants: false,
|
|
60
|
+
crypto: false,
|
|
61
|
+
domain: false,
|
|
62
|
+
events: false,
|
|
63
|
+
http: false,
|
|
64
|
+
https: false,
|
|
65
|
+
os: false,
|
|
66
|
+
path: false,
|
|
67
|
+
punycode: false,
|
|
68
|
+
process: false,
|
|
69
|
+
querystring: false,
|
|
70
|
+
stream: false,
|
|
71
|
+
string_decoder: false,
|
|
72
|
+
sys: false,
|
|
73
|
+
timers: false,
|
|
74
|
+
tty: false,
|
|
75
|
+
url: false,
|
|
76
|
+
util: false,
|
|
77
|
+
vm: false,
|
|
78
|
+
zlib: false
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
// expect these apis in the browser
|
|
82
|
+
externals: {
|
|
83
|
+
'crypto': 'crypto',
|
|
84
|
+
'canvas': 'canvas',
|
|
85
|
+
'fs': 'fs',
|
|
86
|
+
'http': 'http',
|
|
87
|
+
'https': 'https',
|
|
88
|
+
'url': 'url',
|
|
89
|
+
'zlib': 'zlib'
|
|
90
|
+
},
|
|
54
91
|
output: {
|
|
55
92
|
filename: jsFilename,
|
|
56
93
|
path: outDir,
|
|
57
|
-
devtoolModuleFilenameTemplate: devMode ? undefined : prodDevtoolModuleFilenameTemplate
|
|
94
|
+
devtoolModuleFilenameTemplate: devMode ? undefined : prodDevtoolModuleFilenameTemplate,
|
|
95
|
+
clean: true
|
|
58
96
|
},
|
|
59
97
|
performance: {
|
|
60
98
|
hints: false
|
|
@@ -91,7 +129,8 @@ module.exports = (env, args) => {
|
|
|
91
129
|
sourceMap: devMode,
|
|
92
130
|
lessOptions: {
|
|
93
131
|
relativeUrls: false,
|
|
94
|
-
rewriteUrls: 'off'
|
|
132
|
+
rewriteUrls: 'off',
|
|
133
|
+
math: 'always'
|
|
95
134
|
}
|
|
96
135
|
}
|
|
97
136
|
}]
|
|
@@ -112,16 +151,27 @@ module.exports = (env, args) => {
|
|
|
112
151
|
[require.resolve('@babel/preset-env'), {
|
|
113
152
|
debug: false,
|
|
114
153
|
targets: {
|
|
115
|
-
firefox: '
|
|
116
|
-
chrome: '
|
|
117
|
-
|
|
118
|
-
edge: '12',
|
|
119
|
-
safari: '8'
|
|
154
|
+
firefox: '62',
|
|
155
|
+
chrome: '69',
|
|
156
|
+
safari: '12.1'
|
|
120
157
|
}
|
|
121
158
|
}]
|
|
122
159
|
]
|
|
123
160
|
}
|
|
124
161
|
}
|
|
162
|
+
}, {
|
|
163
|
+
// to support css imports (currently not used by Scout but might be used by included 3rd party libs)
|
|
164
|
+
test: /\.css$/i,
|
|
165
|
+
use: [{
|
|
166
|
+
loader: require.resolve('style-loader')
|
|
167
|
+
}, {
|
|
168
|
+
loader: require.resolve('css-loader'),
|
|
169
|
+
options: {
|
|
170
|
+
sourceMap: devMode,
|
|
171
|
+
modules: false, // We don't want to work with CSS modules
|
|
172
|
+
url: false // Don't resolve URLs in LESS, because relative path does not match /res/fonts
|
|
173
|
+
}
|
|
174
|
+
}]
|
|
125
175
|
}]
|
|
126
176
|
},
|
|
127
177
|
plugins: [
|
|
@@ -132,7 +182,8 @@ module.exports = (env, args) => {
|
|
|
132
182
|
],
|
|
133
183
|
optimization: {
|
|
134
184
|
splitChunks: {
|
|
135
|
-
chunks: 'all'
|
|
185
|
+
chunks: 'all',
|
|
186
|
+
name: (module, chunks, cacheGroupKey) => computeChunkName(module, chunks, cacheGroupKey)
|
|
136
187
|
}
|
|
137
188
|
}
|
|
138
189
|
};
|
|
@@ -150,13 +201,13 @@ module.exports = (env, args) => {
|
|
|
150
201
|
}
|
|
151
202
|
|
|
152
203
|
if (!devMode) {
|
|
153
|
-
const
|
|
204
|
+
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|
154
205
|
const TerserPlugin = require('terser-webpack-plugin');
|
|
155
206
|
config.optimization.minimizer = [
|
|
156
207
|
// minify css
|
|
157
|
-
new
|
|
158
|
-
|
|
159
|
-
|
|
208
|
+
new CssMinimizerPlugin({
|
|
209
|
+
test: /\.min\.css$/g,
|
|
210
|
+
minimizerOptions: {
|
|
160
211
|
preset: ['default', {
|
|
161
212
|
discardComments: {removeAll: true}
|
|
162
213
|
}]
|
|
@@ -164,18 +215,11 @@ module.exports = (env, args) => {
|
|
|
164
215
|
}),
|
|
165
216
|
// minify js
|
|
166
217
|
new TerserPlugin({
|
|
167
|
-
test: /\.js(\?.*)?$/i
|
|
168
|
-
cache: true,
|
|
169
|
-
parallel: true
|
|
218
|
+
test: /\.js(\?.*)?$/i
|
|
170
219
|
})
|
|
171
220
|
];
|
|
172
221
|
}
|
|
173
222
|
|
|
174
|
-
if (nvl(args.clean, false)) {
|
|
175
|
-
// see: https://webpack.js.org/guides/output-management/#cleaning-up-the-dist-folder
|
|
176
|
-
config.plugins.push(new CleanWebpackPlugin());
|
|
177
|
-
}
|
|
178
|
-
|
|
179
223
|
if (devMode) {
|
|
180
224
|
// Use external source maps also in dev mode because the browser is very slow in displaying a file containing large lines which is the case if source maps are inlined
|
|
181
225
|
config.plugins.push(new webpack.SourceMapDevToolPlugin({
|
|
@@ -218,14 +262,66 @@ function addThemes(entry, options = {}) {
|
|
|
218
262
|
});
|
|
219
263
|
}
|
|
220
264
|
|
|
265
|
+
function computeChunkName(module, chunks, cacheGroupKey) {
|
|
266
|
+
const entryPointDelim = '~';
|
|
267
|
+
const allChunksNames = chunks
|
|
268
|
+
.map(chunk => chunk.name)
|
|
269
|
+
.filter(chunkName => !!chunkName)
|
|
270
|
+
.join(entryPointDelim);
|
|
271
|
+
let fileName = cacheGroupKey === 'defaultVendors' ? 'vendors' : cacheGroupKey;
|
|
272
|
+
|
|
273
|
+
if (allChunksNames.length < 1) {
|
|
274
|
+
// there is no chunk name (e.g. lazy loaded module): derive chunk-name from filename
|
|
275
|
+
const segmentDelim = '-';
|
|
276
|
+
if (fileName.length > 0) {
|
|
277
|
+
fileName += segmentDelim;
|
|
278
|
+
}
|
|
279
|
+
return fileName + computeModuleId(module);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (fileName.length > 0) {
|
|
283
|
+
fileName += entryPointDelim;
|
|
284
|
+
}
|
|
285
|
+
return fileName + allChunksNames;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function computeModuleId(module) {
|
|
289
|
+
const nodeModules = 'node_modules';
|
|
290
|
+
let id = module.userRequest;
|
|
291
|
+
const nodeModulesPos = id.lastIndexOf(nodeModules);
|
|
292
|
+
if (nodeModulesPos < 0) {
|
|
293
|
+
// use file name
|
|
294
|
+
id = path.basename(id, '.js');
|
|
295
|
+
} else {
|
|
296
|
+
// use js-module name
|
|
297
|
+
id = id.substring(nodeModulesPos + nodeModules.length + path.sep.length);
|
|
298
|
+
let end = id.indexOf(path.sep);
|
|
299
|
+
if (end >= 0) {
|
|
300
|
+
if (id.startsWith('@')) {
|
|
301
|
+
const next = id.indexOf(path.sep, end + 1);
|
|
302
|
+
if (next >= 0) {
|
|
303
|
+
end = next;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
id = id.substring(0, end);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return id.replace(/[/\\\-@:_.|]+/g, '').toLowerCase();
|
|
311
|
+
}
|
|
312
|
+
|
|
221
313
|
function ensureArray(array) {
|
|
222
314
|
if (array === undefined || array === null) {
|
|
223
315
|
return [];
|
|
224
316
|
}
|
|
225
|
-
if (
|
|
226
|
-
return
|
|
317
|
+
if (Array.isArray(array)) {
|
|
318
|
+
return array;
|
|
319
|
+
}
|
|
320
|
+
const isIterable = typeof array[Symbol.iterator] === 'function' && typeof array !== 'string';
|
|
321
|
+
if (isIterable) {
|
|
322
|
+
return Array.from(array);
|
|
227
323
|
}
|
|
228
|
-
return array;
|
|
324
|
+
return [array];
|
|
229
325
|
}
|
|
230
326
|
|
|
231
327
|
function nvl(arg, defaultValue) {
|