total5 0.0.16-8 → 0.0.16
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/aimodel.js +21 -2
- package/builders.js +6 -6
- package/changelog.txt +9 -0
- package/cms.js +9 -9
- package/global.js +17 -7
- package/index.js +2 -0
- package/jsonschema.js +1 -1
- package/package.json +1 -1
- package/utils.js +121 -22
- package/websocket.js +6 -3
- package/workers.js +1 -1
package/aimodel.js
CHANGED
|
@@ -30,13 +30,27 @@ AI.prototype.message = function(role, content, merge) {
|
|
|
30
30
|
if (merge) {
|
|
31
31
|
for (let m of t.payload.messages) {
|
|
32
32
|
if (m.role === role) {
|
|
33
|
-
|
|
33
|
+
|
|
34
|
+
if (typeof(content) === 'object') {
|
|
35
|
+
for (let key in content)
|
|
36
|
+
m[key] = content[key];
|
|
37
|
+
} else
|
|
38
|
+
m.content += merge + content;
|
|
39
|
+
|
|
34
40
|
return this;
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
const msg = { role: role };
|
|
46
|
+
|
|
47
|
+
if (typeof(content) === 'object') {
|
|
48
|
+
for (let key in content)
|
|
49
|
+
msg[key] = content[key];
|
|
50
|
+
} else
|
|
51
|
+
msg.content = content;
|
|
52
|
+
|
|
53
|
+
t.payload.messages.push(msg);
|
|
40
54
|
return t;
|
|
41
55
|
};
|
|
42
56
|
|
|
@@ -55,6 +69,11 @@ AI.prototype.user = function(content, merge) {
|
|
|
55
69
|
return this.message('user', content, merge);
|
|
56
70
|
};
|
|
57
71
|
|
|
72
|
+
AI.prototype.prompt = function(content) {
|
|
73
|
+
this.payload.prompt = content;
|
|
74
|
+
return this;
|
|
75
|
+
};
|
|
76
|
+
|
|
58
77
|
AI.prototype.assistant = function(content, merge) {
|
|
59
78
|
return this.message('assistant', content, merge);
|
|
60
79
|
};
|
package/builders.js
CHANGED
|
@@ -247,7 +247,7 @@ Options.prototype.successful = function(callback) {
|
|
|
247
247
|
};
|
|
248
248
|
};
|
|
249
249
|
|
|
250
|
-
Options.prototype.callback = Options.prototype.pipe = function(value) {
|
|
250
|
+
Options.prototype.callback = Options.prototype.output = Options.prototype.pipe = function(value) {
|
|
251
251
|
|
|
252
252
|
var self = this;
|
|
253
253
|
|
|
@@ -1429,7 +1429,7 @@ ActionCaller.prototype.exec = function() {
|
|
|
1429
1429
|
|
|
1430
1430
|
if (!err) {
|
|
1431
1431
|
if (action.jsoutput)
|
|
1432
|
-
response = action.jsoutput.transform(response).response;
|
|
1432
|
+
response = action.jsoutput.transform(response).response || {};
|
|
1433
1433
|
|
|
1434
1434
|
if (action.extend) {
|
|
1435
1435
|
if (action.extend.includes('.'))
|
|
@@ -1493,7 +1493,7 @@ ActionCaller.prototype.exec = function() {
|
|
|
1493
1493
|
self.cancel();
|
|
1494
1494
|
return;
|
|
1495
1495
|
}
|
|
1496
|
-
$.query = response.response;
|
|
1496
|
+
$.query = response.response || {};
|
|
1497
1497
|
} else
|
|
1498
1498
|
$.query = query;
|
|
1499
1499
|
|
|
@@ -1505,7 +1505,7 @@ ActionCaller.prototype.exec = function() {
|
|
|
1505
1505
|
self.cancel();
|
|
1506
1506
|
return;
|
|
1507
1507
|
}
|
|
1508
|
-
$.params = response.response;
|
|
1508
|
+
$.params = response.response || {};
|
|
1509
1509
|
} else
|
|
1510
1510
|
$.params = params;
|
|
1511
1511
|
|
|
@@ -1515,7 +1515,7 @@ ActionCaller.prototype.exec = function() {
|
|
|
1515
1515
|
self.cancel();
|
|
1516
1516
|
return;
|
|
1517
1517
|
}
|
|
1518
|
-
$.payload = response.response;
|
|
1518
|
+
$.payload = response.response || {};
|
|
1519
1519
|
} else
|
|
1520
1520
|
$.payload = payload;
|
|
1521
1521
|
|
|
@@ -1555,7 +1555,7 @@ ActionCaller.prototype.finish = function(value) {
|
|
|
1555
1555
|
if (self.error.length)
|
|
1556
1556
|
$.invalid(self.error);
|
|
1557
1557
|
else
|
|
1558
|
-
$.callback.call(
|
|
1558
|
+
$.callback.call($, value === undefined ? self.$.response : value);
|
|
1559
1559
|
} else
|
|
1560
1560
|
self.options.callback.call(self.$, self.error.length ? self.error : null, value === undefined ? self.$.response : value);
|
|
1561
1561
|
|
package/changelog.txt
CHANGED
|
@@ -28,6 +28,15 @@
|
|
|
28
28
|
- extended `NEWAPI(type, [config], config)` by adding the `config` argument
|
|
29
29
|
- replaced `Url.parse()` with `new URL()`
|
|
30
30
|
- fixed `NEWFORK()` method
|
|
31
|
+
- fixed callback with `$` in the `ACTION().callback($)`
|
|
32
|
+
- fixed returing a default JSON schema object in actions
|
|
33
|
+
- added support for nested inline action schemas in action schemas
|
|
34
|
+
- fixed loading of `totalapi` key via `LOADCONFIG()`
|
|
35
|
+
- changed `SIGTERM` for `SIGKILL` in the `NEWFORK()` method
|
|
36
|
+
- extended `data` object in the `DEF.onAudit` delegate by adding `sessionid {String}` property
|
|
37
|
+
- fixed promise in the `AJAX()` method
|
|
38
|
+
- added `options.timeout {Number}` to the `WebSocketClient`
|
|
39
|
+
- extended `U.chunker()` by adding `.load([callback])` method for loading existing chunks
|
|
31
40
|
|
|
32
41
|
========================
|
|
33
42
|
0.0.15
|
package/cms.js
CHANGED
|
@@ -755,11 +755,11 @@ CMSRender.prototype._render = function(meta, layout, callback) {
|
|
|
755
755
|
layout = null;
|
|
756
756
|
}
|
|
757
757
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
758
|
+
const self = this;
|
|
759
|
+
const widgets = [];
|
|
760
|
+
let opt = {};
|
|
761
761
|
|
|
762
|
-
for (
|
|
762
|
+
for (const key in meta) {
|
|
763
763
|
if (key !== 'widgets')
|
|
764
764
|
opt[key] = meta[key];
|
|
765
765
|
}
|
|
@@ -775,9 +775,9 @@ CMSRender.prototype._render = function(meta, layout, callback) {
|
|
|
775
775
|
opt.template = item.template;
|
|
776
776
|
opt.cacheid = opt.id;
|
|
777
777
|
|
|
778
|
-
|
|
778
|
+
let render = item.render;
|
|
779
779
|
if (meta.widgets) {
|
|
780
|
-
|
|
780
|
+
const w = meta.widgets instanceof Array ? meta.widgets.findItem('id', item.id) : meta.widgets[item.id];
|
|
781
781
|
if (w) {
|
|
782
782
|
render = w.render;
|
|
783
783
|
if (w.cache === 'url' && opt.url)
|
|
@@ -800,13 +800,13 @@ CMSRender.prototype._render = function(meta, layout, callback) {
|
|
|
800
800
|
|
|
801
801
|
}, function() {
|
|
802
802
|
|
|
803
|
-
|
|
803
|
+
const tangular = [];
|
|
804
804
|
|
|
805
805
|
// opt.inlinecache {Object} user defined cache
|
|
806
806
|
|
|
807
807
|
for (let i = 0; i < self.tangular.length; i++) {
|
|
808
808
|
|
|
809
|
-
|
|
809
|
+
const key = i + '';
|
|
810
810
|
let body = opt.inlinecache ? opt.inlinecache[key] : '';
|
|
811
811
|
|
|
812
812
|
if (!body) {
|
|
@@ -829,7 +829,7 @@ CMSRender.prototype._render = function(meta, layout, callback) {
|
|
|
829
829
|
tangular.push(body);
|
|
830
830
|
}
|
|
831
831
|
|
|
832
|
-
|
|
832
|
+
const html = self.toString(self.text, widgets, tangular, meta.body || '');
|
|
833
833
|
if (layout) {
|
|
834
834
|
meta.body = html;
|
|
835
835
|
layout.render(meta, callback);
|
package/global.js
CHANGED
|
@@ -147,11 +147,21 @@ global.AJAX = function(url, data, callback) {
|
|
|
147
147
|
data = null;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
if (!callback)
|
|
151
|
-
return new Promise((resolve, reject)
|
|
150
|
+
if (!callback) {
|
|
151
|
+
return new Promise(function(resolve, reject) {
|
|
152
|
+
global.AJAX(url, data, function(err, response) {
|
|
153
|
+
if (err) {
|
|
154
|
+
if (err instanceof Array)
|
|
155
|
+
err = ErrorBuilder.assign(err).reject();
|
|
156
|
+
reject(err);
|
|
157
|
+
} else
|
|
158
|
+
resolve(response);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
152
162
|
|
|
153
|
-
|
|
154
|
-
|
|
163
|
+
const index = url.indexOf(' ');
|
|
164
|
+
const opt = {};
|
|
155
165
|
|
|
156
166
|
if (index !== -1) {
|
|
157
167
|
opt.method = url.substring(0, index);
|
|
@@ -175,14 +185,14 @@ global.AJAX = function(url, data, callback) {
|
|
|
175
185
|
return;
|
|
176
186
|
}
|
|
177
187
|
|
|
178
|
-
|
|
188
|
+
let type = err ? '' : response.headers['content-type'] || '';
|
|
179
189
|
if (type) {
|
|
180
|
-
|
|
190
|
+
const index = type.lastIndexOf(';');
|
|
181
191
|
if (index !== -1)
|
|
182
192
|
type = type.substring(0, index).trim();
|
|
183
193
|
}
|
|
184
194
|
|
|
185
|
-
|
|
195
|
+
let value = null;
|
|
186
196
|
|
|
187
197
|
switch (type.toLowerCase()) {
|
|
188
198
|
case 'text/xml':
|
package/index.js
CHANGED
|
@@ -559,6 +559,7 @@ F.loadconfig = function(value) {
|
|
|
559
559
|
key = 'secret_totalapi';
|
|
560
560
|
else
|
|
561
561
|
key = '$tapi';
|
|
562
|
+
cfg[key] = val;
|
|
562
563
|
break;
|
|
563
564
|
case '$tms':
|
|
564
565
|
break;
|
|
@@ -2085,6 +2086,7 @@ F.audit = function(name, $, message, type) {
|
|
|
2085
2086
|
var data = {};
|
|
2086
2087
|
|
|
2087
2088
|
if ($.user) {
|
|
2089
|
+
data.sessionid = $.user.sessionid || $.sessionid || $.controller?.sessionid;
|
|
2088
2090
|
data.userid = $.user.id;
|
|
2089
2091
|
data.createdby = $.user.name || $.user.nick || $.user.alias;
|
|
2090
2092
|
}
|
package/jsonschema.js
CHANGED
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -5110,19 +5110,43 @@ function Chunker(name, max) {
|
|
|
5110
5110
|
|
|
5111
5111
|
const CHP = Chunker.prototype;
|
|
5112
5112
|
|
|
5113
|
+
CHP.load = function(callback) {
|
|
5114
|
+
|
|
5115
|
+
const self = this;
|
|
5116
|
+
|
|
5117
|
+
if (!callback)
|
|
5118
|
+
return new Promise(resolve => self.load(() => resolve()));
|
|
5119
|
+
|
|
5120
|
+
F.Fs.readdir(F.path.tmp(), function(err, files) {
|
|
5121
|
+
|
|
5122
|
+
if (err) {
|
|
5123
|
+
callback(null, 0);
|
|
5124
|
+
return;
|
|
5125
|
+
}
|
|
5126
|
+
|
|
5127
|
+
for (let file of files) {
|
|
5128
|
+
if (file.includes(self.name + '-')) {
|
|
5129
|
+
self.index++;
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
callback(null, self.index);
|
|
5133
|
+
});
|
|
5134
|
+
return self;
|
|
5135
|
+
};
|
|
5136
|
+
|
|
5113
5137
|
CHP.append = CHP.write = function(obj) {
|
|
5114
5138
|
|
|
5115
|
-
|
|
5139
|
+
const self = this;
|
|
5116
5140
|
self.stack.push(obj);
|
|
5117
5141
|
|
|
5118
|
-
|
|
5142
|
+
const tmp = self.stack.length;
|
|
5119
5143
|
if (tmp >= self.max) {
|
|
5120
5144
|
|
|
5121
5145
|
self.flushing++;
|
|
5122
5146
|
self.pages++;
|
|
5123
5147
|
self.count += tmp;
|
|
5124
5148
|
|
|
5125
|
-
|
|
5149
|
+
const index = (self.index++);
|
|
5126
5150
|
|
|
5127
5151
|
if (self.compress) {
|
|
5128
5152
|
F.Zlib.deflate(Buffer.from(JSON.stringify(self.stack), 'utf8'), function(err, buffer) {
|
|
@@ -5138,14 +5162,14 @@ CHP.append = CHP.write = function(obj) {
|
|
|
5138
5162
|
};
|
|
5139
5163
|
|
|
5140
5164
|
CHP.end = function() {
|
|
5141
|
-
|
|
5142
|
-
|
|
5165
|
+
const self = this;
|
|
5166
|
+
const tmp = self.stack.length;
|
|
5143
5167
|
if (tmp) {
|
|
5144
5168
|
self.flushing++;
|
|
5145
5169
|
self.pages++;
|
|
5146
5170
|
self.count += tmp;
|
|
5147
5171
|
|
|
5148
|
-
|
|
5172
|
+
const index = (self.index++);
|
|
5149
5173
|
|
|
5150
5174
|
if (self.compress) {
|
|
5151
5175
|
F.Zlib.deflate(Buffer.from(JSON.stringify(self.stack), 'utf8'), function(err, buffer) {
|
|
@@ -5949,6 +5973,84 @@ exports.connect = function(opt, callback) {
|
|
|
5949
5973
|
meta.socket1.on('clientError', error);
|
|
5950
5974
|
};
|
|
5951
5975
|
|
|
5976
|
+
function extractnested(str, minDepth = 0) {
|
|
5977
|
+
|
|
5978
|
+
const parts = [];
|
|
5979
|
+
|
|
5980
|
+
let out = '';
|
|
5981
|
+
let depth = 0;
|
|
5982
|
+
let capturing = false;
|
|
5983
|
+
let capDepth = 0;
|
|
5984
|
+
let buf = '';
|
|
5985
|
+
|
|
5986
|
+
const isOpen = (c) => c === '[' || c === '{';
|
|
5987
|
+
const isClose = (c) => c === ']' || c === '}';
|
|
5988
|
+
const matches = (o, c) => (o === '[' && c === ']') || (o === '{' && c === '}');
|
|
5989
|
+
const stack = [];
|
|
5990
|
+
|
|
5991
|
+
for (let i = 0; i < str.length; i++) {
|
|
5992
|
+
const ch = str[i];
|
|
5993
|
+
|
|
5994
|
+
if (isOpen(ch)) {
|
|
5995
|
+
|
|
5996
|
+
if (!capturing && depth >= minDepth) {
|
|
5997
|
+
capturing = true;
|
|
5998
|
+
capDepth = depth + 1;
|
|
5999
|
+
buf = '';
|
|
6000
|
+
}
|
|
6001
|
+
|
|
6002
|
+
stack.push(ch);
|
|
6003
|
+
depth++;
|
|
6004
|
+
|
|
6005
|
+
if (capturing) buf += ch;
|
|
6006
|
+
else out += ch;
|
|
6007
|
+
|
|
6008
|
+
continue;
|
|
6009
|
+
}
|
|
6010
|
+
|
|
6011
|
+
if (isClose(ch)) {
|
|
6012
|
+
|
|
6013
|
+
const open = stack[stack.length - 1];
|
|
6014
|
+
if (!open || !matches(open, ch))
|
|
6015
|
+
throw new Error(`Mismatched/unbalanced brackets at index ${i}`);
|
|
6016
|
+
|
|
6017
|
+
if (capturing) buf += ch;
|
|
6018
|
+
else out += ch;
|
|
6019
|
+
|
|
6020
|
+
stack.pop();
|
|
6021
|
+
depth--;
|
|
6022
|
+
|
|
6023
|
+
if (capturing && depth < capDepth) {
|
|
6024
|
+
|
|
6025
|
+
const inner = buf.slice(1, -1);
|
|
6026
|
+
const type = buf[0];
|
|
6027
|
+
const startsWithRef = inner.trimStart().startsWith('@');
|
|
6028
|
+
const hasEnumPipe = type === '{' && inner.includes('|');
|
|
6029
|
+
|
|
6030
|
+
if (!startsWithRef && !hasEnumPipe) {
|
|
6031
|
+
const idx = parts.length;
|
|
6032
|
+
out += type + `#${idx}` + (type === '{' ? '}' : ']');
|
|
6033
|
+
parts.push(inner);
|
|
6034
|
+
} else
|
|
6035
|
+
out += buf;
|
|
6036
|
+
|
|
6037
|
+
capturing = false;
|
|
6038
|
+
buf = '';
|
|
6039
|
+
}
|
|
6040
|
+
|
|
6041
|
+
continue;
|
|
6042
|
+
}
|
|
6043
|
+
|
|
6044
|
+
if (capturing) buf += ch;
|
|
6045
|
+
else out += ch;
|
|
6046
|
+
}
|
|
6047
|
+
|
|
6048
|
+
if (stack.length)
|
|
6049
|
+
throw new Error('Unbalanced opening bracket(s)');
|
|
6050
|
+
|
|
6051
|
+
return { text: out, parts };
|
|
6052
|
+
}
|
|
6053
|
+
|
|
5952
6054
|
SP.toJSONSchema = SP.parseSchema = function(name, url) {
|
|
5953
6055
|
|
|
5954
6056
|
let obj = {};
|
|
@@ -5963,19 +6065,11 @@ SP.toJSONSchema = SP.parseSchema = function(name, url) {
|
|
|
5963
6065
|
obj.properties = {};
|
|
5964
6066
|
|
|
5965
6067
|
let str = this;
|
|
5966
|
-
let nestedtypes
|
|
5967
|
-
|
|
5968
|
-
str = str.replace(/\[.*?\]/g, function(text) {
|
|
5969
|
-
if (text.substring(1, 2) === '@')
|
|
5970
|
-
return text;
|
|
5971
|
-
return '[#' + (nestedtypes.push(text.substring(1, text.length - 1)) - 1) + ']';
|
|
5972
|
-
});
|
|
6068
|
+
let nestedtypes;
|
|
5973
6069
|
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
return '{#' + (nestedtypes.push(text.substring(1, text.length - 1)) - 1) + '}';
|
|
5978
|
-
});
|
|
6070
|
+
let extracted = extractnested(str);
|
|
6071
|
+
nestedtypes = extracted.parts;
|
|
6072
|
+
str = extracted.text;
|
|
5979
6073
|
|
|
5980
6074
|
let prop = str.split(/,|\n/);
|
|
5981
6075
|
let required = [];
|
|
@@ -6026,15 +6120,20 @@ SP.toJSONSchema = SP.parseSchema = function(name, url) {
|
|
|
6026
6120
|
// let type = typename.toLowerCase().trim();
|
|
6027
6121
|
let size = 0;
|
|
6028
6122
|
let isarr = type[0] === '[';
|
|
6029
|
-
if (isarr)
|
|
6030
|
-
type = type.substring(1, type.
|
|
6123
|
+
if (isarr) {
|
|
6124
|
+
type = type.substring(1, type.indexOf(']'));
|
|
6125
|
+
}
|
|
6031
6126
|
|
|
6032
6127
|
let nestedschema = '';
|
|
6033
6128
|
let isenum = type[0] === '{';
|
|
6034
6129
|
|
|
6035
6130
|
if (isenum) {
|
|
6036
|
-
|
|
6037
|
-
|
|
6131
|
+
|
|
6132
|
+
if (type[1] === '@' || type[1] === '#') {
|
|
6133
|
+
tmp = type.substring(2, type.indexOf('}'));
|
|
6134
|
+
tmp = nestedtypes[+tmp];
|
|
6135
|
+
} else
|
|
6136
|
+
tmp = type.substring(1, type.indexOf('}'));
|
|
6038
6137
|
|
|
6039
6138
|
// Nested schema
|
|
6040
6139
|
if ((/[:,\s]/).test(tmp)) {
|
package/websocket.js
CHANGED
|
@@ -169,7 +169,7 @@ function websocket_ondata(chunk) {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
function websocket_onerror(e) {
|
|
172
|
-
this.destroy &&
|
|
172
|
+
this.destroy && this.destroy();
|
|
173
173
|
this.$controller && this.$controller.onerror(e);
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -1212,7 +1212,7 @@ function WebSocketClient() {
|
|
|
1212
1212
|
|
|
1213
1213
|
// type: json, text, binary
|
|
1214
1214
|
t.headers = {};
|
|
1215
|
-
t.options = { type: 'json', size: 0, masking: false, compress: true, reconnect: 3000, encodedecode: false, encryptdecrypt: false, rejectunauthorized: false }; // key: Buffer, cert: Buffer, dhparam: Buffer
|
|
1215
|
+
t.options = { type: 'json', size: 0, masking: false, compress: true, reconnect: 3000, encodedecode: false, encryptdecrypt: false, rejectunauthorized: false, timeout: 30000 }; // key: Buffer, cert: Buffer, dhparam: Buffer
|
|
1216
1216
|
t.cookies = {};
|
|
1217
1217
|
|
|
1218
1218
|
t.ondata2 = () => t.ondata();
|
|
@@ -1294,7 +1294,6 @@ WebSocketClient.prototype.connectforce = function(self, url, protocol, origin) {
|
|
|
1294
1294
|
F.stats.performance.online++;
|
|
1295
1295
|
self.req = (secured ? F.Https : F.Http).get(options);
|
|
1296
1296
|
self.req.$main = self;
|
|
1297
|
-
|
|
1298
1297
|
self.req.on('error', function(e) {
|
|
1299
1298
|
self.$events.error && self.emit('error', e);
|
|
1300
1299
|
self.onclose();
|
|
@@ -1337,6 +1336,10 @@ WebSocketClient.prototype.connectforce = function(self, url, protocol, origin) {
|
|
|
1337
1336
|
}
|
|
1338
1337
|
|
|
1339
1338
|
self.closed = false;
|
|
1339
|
+
|
|
1340
|
+
if (self.options.timeout > 0)
|
|
1341
|
+
self.socket.setKeepAlive(true, self.options.timeout);
|
|
1342
|
+
|
|
1340
1343
|
self.socket.on('data', websocket_ondata);
|
|
1341
1344
|
self.socket.on('error', websocket_onerror);
|
|
1342
1345
|
self.socket.on('close', wsclient_close);
|
package/workers.js
CHANGED
|
@@ -63,7 +63,7 @@ exports.createfork = function(name) {
|
|
|
63
63
|
const filename = name[0] === '~' ? name.substring(1) : F.path.root('workers/' + name + '.js');
|
|
64
64
|
const fork = new F.Child.fork(filename, { cwd: HEADER.cwd, argv: ['--worker'] });
|
|
65
65
|
fork.postMessage = fork.send;
|
|
66
|
-
fork.terminate = () => fork.kill('
|
|
66
|
+
fork.terminate = () => fork.kill('SIGKILL');
|
|
67
67
|
return fork;
|
|
68
68
|
};
|
|
69
69
|
|