@nocobase/plugin-workflow 0.7.4-alpha.7 → 0.7.6-alpha.1
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.d.ts +0 -0
- package/client.js +0 -0
- package/lib/client/calculators.d.ts +7 -9
- package/lib/client/calculators.js +118 -207
- package/lib/client/components/CollectionFieldset.d.ts +3 -0
- package/lib/client/components/CollectionFieldset.js +257 -0
- package/lib/client/index.d.ts +1 -0
- package/lib/client/index.js +10 -1
- package/lib/client/nodes/create.js +3 -3
- package/lib/client/nodes/index.js +3 -2
- package/lib/client/nodes/update.js +5 -1
- package/lib/client/triggers/collection.js +1 -1
- package/lib/client/triggers/schedule/EndsByField.js +13 -1
- package/lib/server/Plugin.d.ts +3 -1
- package/lib/server/Plugin.js +2 -1
- package/lib/server/Processor.d.ts +2 -1
- package/lib/server/actions/workflows.js +23 -2
- package/lib/server/calculators/index.js +3 -2
- package/lib/server/instructions/create.js +1 -0
- package/lib/server/instructions/destroy.js +1 -0
- package/lib/server/instructions/index.d.ts +5 -3
- package/lib/server/instructions/index.js +2 -3
- package/lib/server/instructions/query.js +1 -0
- package/lib/server/instructions/update.js +1 -0
- package/lib/server/triggers/collection.js +22 -9
- package/lib/server/triggers/schedule.d.ts +4 -2
- package/lib/server/triggers/schedule.js +175 -181
- package/package.json +8 -8
- package/server.d.ts +0 -0
- package/server.js +0 -0
package/lib/client/index.js
CHANGED
|
@@ -4,8 +4,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
var _exportNames = {
|
|
7
|
-
triggers: true
|
|
7
|
+
triggers: true,
|
|
8
|
+
calculators: true
|
|
8
9
|
};
|
|
10
|
+
Object.defineProperty(exports, "calculators", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function get() {
|
|
13
|
+
return _calculators.calculators;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
9
16
|
Object.defineProperty(exports, "default", {
|
|
10
17
|
enumerable: true,
|
|
11
18
|
get: function get() {
|
|
@@ -35,4 +42,6 @@ Object.keys(_nodes).forEach(function (key) {
|
|
|
35
42
|
});
|
|
36
43
|
});
|
|
37
44
|
|
|
45
|
+
var _calculators = require("./calculators");
|
|
46
|
+
|
|
38
47
|
var _WorkflowProvider = require("./WorkflowProvider");
|
|
@@ -25,14 +25,14 @@ function _client() {
|
|
|
25
25
|
return data;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
var _calculators = require("../calculators");
|
|
29
|
-
|
|
30
28
|
var _collection = require("../schemas/collection");
|
|
31
29
|
|
|
32
30
|
var _WorkflowCanvas = require("../WorkflowCanvas");
|
|
33
31
|
|
|
34
32
|
var _CollectionFieldSelect = _interopRequireDefault(require("../components/CollectionFieldSelect"));
|
|
35
33
|
|
|
34
|
+
var _CollectionFieldset = _interopRequireDefault(require("../components/CollectionFieldset"));
|
|
35
|
+
|
|
36
36
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
37
37
|
|
|
38
38
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
@@ -66,7 +66,7 @@ var _default = {
|
|
|
66
66
|
useCollectionDataSource: _client().useCollectionDataSource
|
|
67
67
|
},
|
|
68
68
|
components: {
|
|
69
|
-
CollectionFieldset:
|
|
69
|
+
CollectionFieldset: _CollectionFieldset.default
|
|
70
70
|
},
|
|
71
71
|
|
|
72
72
|
getter(props) {
|
|
@@ -154,9 +154,10 @@ function useUpdateAction() {
|
|
|
154
154
|
_antd().message.error(t('Node in executed workflow cannot be modified'));
|
|
155
155
|
|
|
156
156
|
return;
|
|
157
|
-
}
|
|
157
|
+
} // TODO: how to do validation separately for each field? especially disabled for dynamic fields?
|
|
158
|
+
// await form.submit();
|
|
159
|
+
|
|
158
160
|
|
|
159
|
-
yield form.submit();
|
|
160
161
|
yield api.resource('flow_nodes', data.id).update({
|
|
161
162
|
filterByTk: data.id,
|
|
162
163
|
values: {
|
|
@@ -19,6 +19,10 @@ var _calculators = require("../calculators");
|
|
|
19
19
|
|
|
20
20
|
var _collection = require("../schemas/collection");
|
|
21
21
|
|
|
22
|
+
var _CollectionFieldset = _interopRequireDefault(require("../components/CollectionFieldset"));
|
|
23
|
+
|
|
24
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
+
|
|
22
26
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
23
27
|
|
|
24
28
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
@@ -42,7 +46,7 @@ var _default = {
|
|
|
42
46
|
},
|
|
43
47
|
components: {
|
|
44
48
|
VariableComponent: _calculators.VariableComponent,
|
|
45
|
-
CollectionFieldset:
|
|
49
|
+
CollectionFieldset: _CollectionFieldset.default
|
|
46
50
|
}
|
|
47
51
|
};
|
|
48
52
|
exports.default = _default;
|
|
@@ -103,7 +103,7 @@ const FieldsSelect = (0, _react2().observer)(props => {
|
|
|
103
103
|
className: (0, _css().css)`
|
|
104
104
|
min-width: 6em;
|
|
105
105
|
`
|
|
106
|
-
}), fields.filter(field => !field.hidden && (field.uiSchema ? !field.uiSchema['x-read-pretty'] : true)).map(field => {
|
|
106
|
+
}), fields.filter(field => !field.hidden && (field.uiSchema ? !field.uiSchema['x-read-pretty'] : true) && !['linkTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(field.type)).map(field => {
|
|
107
107
|
var _field$uiSchema;
|
|
108
108
|
|
|
109
109
|
return _react().default.createElement(_antd().Select.Option, {
|
|
@@ -25,6 +25,16 @@ function _antd() {
|
|
|
25
25
|
return data;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function _moment() {
|
|
29
|
+
const data = _interopRequireDefault(require("moment"));
|
|
30
|
+
|
|
31
|
+
_moment = function _moment() {
|
|
32
|
+
return data;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
function _react() {
|
|
29
39
|
const data = _interopRequireWildcard(require("react"));
|
|
30
40
|
|
|
@@ -51,6 +61,8 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
|
|
|
51
61
|
|
|
52
62
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
53
63
|
|
|
64
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
65
|
+
|
|
54
66
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
55
67
|
|
|
56
68
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
@@ -96,7 +108,7 @@ function EndsByField({
|
|
|
96
108
|
onChange: _onChange
|
|
97
109
|
}) : _react().default.createElement(_antd().DatePicker, {
|
|
98
110
|
showTime: true,
|
|
99
|
-
value: value,
|
|
111
|
+
value: (0, _moment().default)(value),
|
|
100
112
|
onChange: _onChange
|
|
101
113
|
}));
|
|
102
114
|
}
|
package/lib/server/Plugin.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export default class WorkflowPlugin extends Plugin {
|
|
|
15
15
|
getName(): string;
|
|
16
16
|
load(): Promise<void>;
|
|
17
17
|
toggle(workflow: WorkflowModel, enable?: boolean): void;
|
|
18
|
-
trigger(workflow: WorkflowModel, context: Object, options?: Transactionable
|
|
18
|
+
trigger(workflow: WorkflowModel, context: Object, options?: Transactionable & {
|
|
19
|
+
context?: any;
|
|
20
|
+
}): Promise<ExecutionModel | null>;
|
|
19
21
|
createProcessor(execution: ExecutionModel, options?: {}): Processor;
|
|
20
22
|
}
|
package/lib/server/Plugin.js
CHANGED
|
@@ -272,7 +272,8 @@ class WorkflowPlugin extends _server().Plugin {
|
|
|
272
272
|
execution.workflow = workflow;
|
|
273
273
|
|
|
274
274
|
const processor = _this3.createProcessor(execution, {
|
|
275
|
-
transaction
|
|
275
|
+
transaction,
|
|
276
|
+
_context: options.context
|
|
276
277
|
});
|
|
277
278
|
|
|
278
279
|
yield processor.start(); // @ts-ignore
|
|
@@ -4,11 +4,12 @@ import ExecutionModel from './models/Execution';
|
|
|
4
4
|
import JobModel from './models/Job';
|
|
5
5
|
import FlowNodeModel from './models/FlowNode';
|
|
6
6
|
export interface ProcessorOptions extends Transactionable {
|
|
7
|
+
_context?: any;
|
|
7
8
|
plugin: Plugin;
|
|
8
9
|
}
|
|
9
10
|
export default class Processor {
|
|
10
11
|
execution: ExecutionModel;
|
|
11
|
-
|
|
12
|
+
options: ProcessorOptions;
|
|
12
13
|
static StatusMap: {
|
|
13
14
|
[x: number]: number;
|
|
14
15
|
};
|
|
@@ -75,7 +75,20 @@ function migrateConfig(config, oldToNew) {
|
|
|
75
75
|
return value.map(item => migrate(item));
|
|
76
76
|
|
|
77
77
|
case 'string':
|
|
78
|
-
|
|
78
|
+
const matcher = value.match(/(\{\{\$jobsMapByNodeId\.)([\w-]+)/);
|
|
79
|
+
|
|
80
|
+
if (!matcher) {
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const oldNodeId = Number.parseInt(matcher[2], 10);
|
|
85
|
+
const newNode = oldToNew.get(oldNodeId);
|
|
86
|
+
|
|
87
|
+
if (!newNode) {
|
|
88
|
+
throw new Error('node configurated for result is not existed');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return value.replace(matcher[0], `{{$jobsMapByNodeId.${newNode.id}`);
|
|
79
92
|
|
|
80
93
|
default:
|
|
81
94
|
return value;
|
|
@@ -171,10 +184,18 @@ function _revision() {
|
|
|
171
184
|
const oldNode = originalNodesMap.get(oldId);
|
|
172
185
|
const newUpstream = oldNode.upstreamId ? oldToNew.get(oldNode.upstreamId) : null;
|
|
173
186
|
const newDownstream = oldNode.downstreamId ? oldToNew.get(oldNode.downstreamId) : null;
|
|
187
|
+
let migratedConfig;
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
migratedConfig = migrateConfig(oldNode.config, oldToNew);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
return context.throw(400, err.message);
|
|
193
|
+
}
|
|
194
|
+
|
|
174
195
|
yield newNode.update({
|
|
175
196
|
upstreamId: (_newUpstream$id = newUpstream === null || newUpstream === void 0 ? void 0 : newUpstream.id) !== null && _newUpstream$id !== void 0 ? _newUpstream$id : null,
|
|
176
197
|
downstreamId: (_newDownstream$id = newDownstream === null || newDownstream === void 0 ? void 0 : newDownstream.id) !== null && _newDownstream$id !== void 0 ? _newDownstream$id : null,
|
|
177
|
-
config:
|
|
198
|
+
config: migratedConfig
|
|
178
199
|
}, {
|
|
179
200
|
transaction
|
|
180
201
|
});
|
|
@@ -177,8 +177,9 @@ calculators.register('notStartsWith', notStartsWith);
|
|
|
177
177
|
calculators.register('endsWith', endsWith);
|
|
178
178
|
calculators.register('notEndsWith', notEndsWith);
|
|
179
179
|
|
|
180
|
-
function
|
|
181
|
-
return a
|
|
180
|
+
function concat(a, b) {
|
|
181
|
+
return a.concat(b);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
calculators.register('concat', concat);
|
|
184
185
|
calculators.register('now', () => new Date()); // TODO: add more common calculators
|
|
@@ -27,6 +27,7 @@ var _default = {
|
|
|
27
27
|
const repo = node.constructor.database.getRepository(collection);
|
|
28
28
|
const options = processor.getParsedValue(params);
|
|
29
29
|
const result = yield repo.create(_objectSpread(_objectSpread({}, options), {}, {
|
|
30
|
+
context: processor.options._context,
|
|
30
31
|
transaction: processor.transaction
|
|
31
32
|
}));
|
|
32
33
|
return {
|
|
@@ -27,6 +27,7 @@ var _default = {
|
|
|
27
27
|
const repo = node.constructor.database.getRepository(collection);
|
|
28
28
|
const options = processor.getParsedValue(params);
|
|
29
29
|
const result = yield repo.destroy(_objectSpread(_objectSpread({}, options), {}, {
|
|
30
|
+
context: processor.options._context,
|
|
30
31
|
transaction: processor.transaction
|
|
31
32
|
}));
|
|
32
33
|
return {
|
|
@@ -11,8 +11,10 @@ export interface Instruction {
|
|
|
11
11
|
run(node: FlowNodeModel, input: any, processor: Processor): InstructionResult;
|
|
12
12
|
resume?(node: FlowNodeModel, input: any, processor: Processor): InstructionResult;
|
|
13
13
|
}
|
|
14
|
+
declare type InstructionConstructor<T> = {
|
|
15
|
+
new (p: Plugin): T;
|
|
16
|
+
};
|
|
14
17
|
export default function <T extends Instruction>(plugin: any, more?: {
|
|
15
|
-
[key: string]: T |
|
|
16
|
-
new (p: Plugin): T;
|
|
17
|
-
};
|
|
18
|
+
[key: string]: T | InstructionConstructor<T>;
|
|
18
19
|
}): void;
|
|
20
|
+
export {};
|
|
@@ -48,15 +48,14 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
48
48
|
function _default(plugin, more = {}) {
|
|
49
49
|
const instructions = plugin.instructions;
|
|
50
50
|
const natives = ['calculation', 'condition', 'parallel', 'delay', 'prompt', 'query', 'create', 'update', 'destroy'].reduce((result, key) => Object.assign(result, {
|
|
51
|
-
[key]: key
|
|
51
|
+
[key]: (0, _utils().requireModule)(_path().default.isAbsolute(key) ? key : _path().default.join(__dirname, key))
|
|
52
52
|
}), {});
|
|
53
53
|
|
|
54
54
|
for (var _i = 0, _Object$entries = Object.entries(_objectSpread(_objectSpread({}, more), natives)); _i < _Object$entries.length; _i++) {
|
|
55
55
|
const _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
56
56
|
name = _Object$entries$_i[0],
|
|
57
|
-
|
|
57
|
+
instruction = _Object$entries$_i[1];
|
|
58
58
|
|
|
59
|
-
const instruction = typeof value === 'string' ? (0, _utils().requireModule)(_path().default.isAbsolute(value) ? value : _path().default.join(__dirname, value)) : value;
|
|
60
59
|
instructions.register(name, typeof instruction === 'function' ? new instruction(plugin) : instruction);
|
|
61
60
|
}
|
|
62
61
|
}
|
|
@@ -28,6 +28,7 @@ var _default = {
|
|
|
28
28
|
const repo = node.constructor.database.getRepository(collection);
|
|
29
29
|
const options = processor.getParsedValue(params);
|
|
30
30
|
const result = yield (multiple ? repo.find : repo.findOne).call(repo, _objectSpread(_objectSpread({}, options), {}, {
|
|
31
|
+
context: processor.options._context,
|
|
31
32
|
transaction: processor.transaction
|
|
32
33
|
})); // NOTE: `toJSON()` to avoid getting undefined value from Proxied model instance (#380)
|
|
33
34
|
// e.g. Object.prototype.hasOwnProperty.call(result, 'id') // false
|
|
@@ -29,6 +29,7 @@ var _default = {
|
|
|
29
29
|
const repo = node.constructor.database.getRepository(collection);
|
|
30
30
|
const options = processor.getParsedValue(params);
|
|
31
31
|
const result = yield repo.update(_objectSpread(_objectSpread({}, options), {}, {
|
|
32
|
+
context: processor.options._context,
|
|
32
33
|
transaction: processor.transaction
|
|
33
34
|
}));
|
|
34
35
|
return {
|
|
@@ -37,6 +37,16 @@ MODE_BITMAP_EVENTS.set(MODE_BITMAP.DESTROY, 'afterDestroy');
|
|
|
37
37
|
|
|
38
38
|
function getHookId(workflow, type) {
|
|
39
39
|
return `${type}#${workflow.id}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getFieldRawName(collection, name) {
|
|
43
|
+
const field = collection.getField(name);
|
|
44
|
+
|
|
45
|
+
if (field && field.type === 'belongsTo') {
|
|
46
|
+
return field.foreignKey;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return name;
|
|
40
50
|
} // async function, should return promise
|
|
41
51
|
|
|
42
52
|
|
|
@@ -49,29 +59,31 @@ function _handler() {
|
|
|
49
59
|
var _condition$$and;
|
|
50
60
|
|
|
51
61
|
const _workflow$config3 = workflow.config,
|
|
52
|
-
|
|
62
|
+
collectionName = _workflow$config3.collection,
|
|
53
63
|
condition = _workflow$config3.condition,
|
|
54
|
-
changed = _workflow$config3.changed;
|
|
64
|
+
changed = _workflow$config3.changed;
|
|
65
|
+
const collection = data.constructor.database.getCollection(collectionName); // NOTE: if no configured fields changed, do not trigger
|
|
55
66
|
|
|
56
|
-
if (changed && changed.length && changed.every(name => !data.
|
|
57
|
-
//
|
|
67
|
+
if (changed && changed.length && changed.filter(name => !['linkTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(collection.getField(name).type)).every(name => !data.changedWithAssociations(getFieldRawName(collection, name)))) {
|
|
68
|
+
// TODO: temp comment out
|
|
69
|
+
return;
|
|
58
70
|
} // NOTE: if no configured condition match, do not trigger
|
|
59
71
|
|
|
60
72
|
|
|
61
73
|
if (condition && ((_condition$$and = condition.$and) === null || _condition$$and === void 0 ? void 0 : _condition$$and.length)) {
|
|
62
74
|
// TODO: change to map filter format to calculation format
|
|
63
75
|
// const calculation = toCalculation(condition);
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const transaction = options.transaction;
|
|
76
|
+
const repository = collection.repository,
|
|
77
|
+
model = collection.model;
|
|
78
|
+
const transaction = options.transaction,
|
|
79
|
+
context = options.context;
|
|
69
80
|
const count = yield repository.count({
|
|
70
81
|
filter: {
|
|
71
82
|
$and: [condition, {
|
|
72
83
|
[model.primaryKeyAttribute]: data[model.primaryKeyAttribute]
|
|
73
84
|
}]
|
|
74
85
|
},
|
|
86
|
+
context,
|
|
75
87
|
transaction
|
|
76
88
|
});
|
|
77
89
|
|
|
@@ -83,6 +95,7 @@ function _handler() {
|
|
|
83
95
|
return this.plugin.trigger(workflow, {
|
|
84
96
|
data: data.get()
|
|
85
97
|
}, {
|
|
98
|
+
context: options.context,
|
|
86
99
|
transaction: options.transaction
|
|
87
100
|
});
|
|
88
101
|
});
|
|
@@ -15,9 +15,10 @@ export declare const SCHEDULE_MODE: {
|
|
|
15
15
|
readonly CONSTANT: 0;
|
|
16
16
|
readonly COLLECTION_FIELD: 1;
|
|
17
17
|
};
|
|
18
|
+
declare function matchNext(this: ScheduleTrigger, workflow: any, now: Date, range?: number): boolean;
|
|
18
19
|
export default class ScheduleTrigger extends Trigger {
|
|
19
|
-
static CacheRules: ((workflow: any, now: any) => any)[];
|
|
20
|
-
static TriggerRules: ((workflow: any, now: any) =>
|
|
20
|
+
static CacheRules: (typeof matchNext | ((workflow: any, now: any) => any))[];
|
|
21
|
+
static TriggerRules: ((workflow: any, now: any) => any)[];
|
|
21
22
|
events: Map<any, any>;
|
|
22
23
|
private timer;
|
|
23
24
|
private cache;
|
|
@@ -36,3 +37,4 @@ export default class ScheduleTrigger extends Trigger {
|
|
|
36
37
|
on(workflow: any): void;
|
|
37
38
|
off(workflow: any): void;
|
|
38
39
|
}
|
|
40
|
+
export {};
|