@bedrockio/model 0.1.9 → 0.1.11
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/dist/cjs/search.js +4 -2
- package/dist/cjs/validation.js +33 -22
- package/package.json +1 -1
- package/src/search.js +4 -2
- package/src/validation.js +65 -36
- package/types/validation.d.ts +91 -1
- package/types/validation.d.ts.map +1 -1
- package/yarn-error.log +979 -1038
package/dist/cjs/search.js
CHANGED
|
@@ -107,13 +107,15 @@ function validateDefinition(definition) {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
function resolveSort(sort, schema) {
|
|
110
|
-
if (!
|
|
110
|
+
if (!sort) {
|
|
111
|
+
sort = [];
|
|
112
|
+
} else if (!Array.isArray(sort)) {
|
|
111
113
|
sort = [sort];
|
|
112
114
|
}
|
|
113
115
|
for (let {
|
|
114
116
|
field
|
|
115
117
|
} of sort) {
|
|
116
|
-
if (!schema.path(field)) {
|
|
118
|
+
if (!field || !schema.path(field)) {
|
|
117
119
|
throw new Error(`Unknown sort field "${field}".`);
|
|
118
120
|
}
|
|
119
121
|
}
|
package/dist/cjs/validation.js
CHANGED
|
@@ -19,31 +19,33 @@ var _softDelete = require("./soft-delete");
|
|
|
19
19
|
var _utils = require("./utils");
|
|
20
20
|
var _include = require("./include");
|
|
21
21
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
-
const
|
|
22
|
+
const DATE_TAGS = {
|
|
23
23
|
'x-schema': 'DateTime',
|
|
24
24
|
'x-description': 'A `string` in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.'
|
|
25
|
+
};
|
|
26
|
+
const OBJECT_ID_SCHEMA = _yada.default.string().mongo().tag({
|
|
27
|
+
'x-schema': 'ObjectId',
|
|
28
|
+
'x-description': 'A 24 character hexadecimal string representing a Mongo [ObjectId](https://bit.ly/3YPtGlU).'
|
|
25
29
|
});
|
|
26
|
-
|
|
30
|
+
exports.OBJECT_ID_SCHEMA = OBJECT_ID_SCHEMA;
|
|
31
|
+
const REFERENCE_SCHEMA = _yada.default.allow(OBJECT_ID_SCHEMA, _yada.default.object({
|
|
32
|
+
id: OBJECT_ID_SCHEMA.required()
|
|
33
|
+
}).custom(obj => {
|
|
34
|
+
return obj.id;
|
|
35
|
+
})).tag({
|
|
36
|
+
'x-schema': 'Reference',
|
|
37
|
+
'x-description': `
|
|
27
38
|
A 24 character hexadecimal string representing a Mongo [ObjectId](https://bit.ly/3YPtGlU).
|
|
28
39
|
An object with an \`id\` field may also be passed, which will be converted into a string.
|
|
29
|
-
|
|
30
|
-
const OBJECT_ID_SCHEMA = _yada.default.custom(async val => {
|
|
31
|
-
const id = String(val.id || val);
|
|
32
|
-
await namedSchemas.objectId.validate(id);
|
|
33
|
-
return id;
|
|
34
|
-
}).tag({
|
|
35
|
-
type: 'ObjectId',
|
|
36
|
-
'x-schema': 'ObjectId',
|
|
37
|
-
'x-description': OBJECT_ID_DESCRIPTION.trim()
|
|
40
|
+
`.trim()
|
|
38
41
|
});
|
|
39
|
-
exports.OBJECT_ID_SCHEMA = OBJECT_ID_SCHEMA;
|
|
40
42
|
const namedSchemas = {
|
|
41
43
|
// Email is special as we are assuming that in
|
|
42
44
|
// all cases lowercase should be allowed but coerced.
|
|
43
45
|
email: _yada.default.string().lowercase().email(),
|
|
44
46
|
// Force "objectId" to have parity with refs.
|
|
45
47
|
// "mongo" is notably excluded here for this reason.
|
|
46
|
-
objectId:
|
|
48
|
+
objectId: OBJECT_ID_SCHEMA,
|
|
47
49
|
ascii: _yada.default.string().ascii(),
|
|
48
50
|
base64: _yada.default.string().base64(),
|
|
49
51
|
btc: _yada.default.string().btc(),
|
|
@@ -77,6 +79,7 @@ function applyValidation(schema, definition) {
|
|
|
77
79
|
allowIncludes: true,
|
|
78
80
|
stripDeleted: true,
|
|
79
81
|
stripTimestamps: true,
|
|
82
|
+
allowExpandedRefs: true,
|
|
80
83
|
requireWriteAccess: true,
|
|
81
84
|
...(hasUnique && {
|
|
82
85
|
assertUniqueOptions: {
|
|
@@ -94,6 +97,7 @@ function applyValidation(schema, definition) {
|
|
|
94
97
|
stripUnknown: true,
|
|
95
98
|
stripDeleted: true,
|
|
96
99
|
stripTimestamps: true,
|
|
100
|
+
allowExpandedRefs: true,
|
|
97
101
|
requireWriteAccess: true,
|
|
98
102
|
...(hasUnique && {
|
|
99
103
|
assertUniqueOptions: {
|
|
@@ -213,7 +217,7 @@ function getObjectSchema(arg, options) {
|
|
|
213
217
|
}
|
|
214
218
|
return schema;
|
|
215
219
|
} else {
|
|
216
|
-
return getSchemaForType(arg);
|
|
220
|
+
return getSchemaForType(arg, options);
|
|
217
221
|
}
|
|
218
222
|
}
|
|
219
223
|
function getArraySchema(arr, options) {
|
|
@@ -247,11 +251,14 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
247
251
|
} else if (typeof type === 'object') {
|
|
248
252
|
schema = getObjectSchema(type, options);
|
|
249
253
|
} else {
|
|
250
|
-
schema = getSchemaForType(type);
|
|
254
|
+
schema = getSchemaForType(type, options);
|
|
251
255
|
}
|
|
252
256
|
if (isRequired(typedef, options)) {
|
|
253
257
|
schema = schema.required();
|
|
254
258
|
}
|
|
259
|
+
if (typedef.default) {
|
|
260
|
+
schema = schema.default(typedef.default);
|
|
261
|
+
}
|
|
255
262
|
if (typedef.validate?.schema) {
|
|
256
263
|
schema = schema.append(typedef.validate.schema);
|
|
257
264
|
} else if (typeof typedef.validate === 'function') {
|
|
@@ -280,7 +287,7 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
280
287
|
}
|
|
281
288
|
return schema;
|
|
282
289
|
}
|
|
283
|
-
function getSchemaForType(type) {
|
|
290
|
+
function getSchemaForType(type, options) {
|
|
284
291
|
switch (type) {
|
|
285
292
|
case 'String':
|
|
286
293
|
return _yada.default.string();
|
|
@@ -289,14 +296,18 @@ function getSchemaForType(type) {
|
|
|
289
296
|
case 'Boolean':
|
|
290
297
|
return _yada.default.boolean();
|
|
291
298
|
case 'Date':
|
|
292
|
-
return
|
|
299
|
+
return _yada.default.date().iso().tag(DATE_TAGS);
|
|
293
300
|
case 'Mixed':
|
|
294
301
|
case 'Object':
|
|
295
302
|
return _yada.default.object();
|
|
296
303
|
case 'Array':
|
|
297
304
|
return _yada.default.array();
|
|
298
305
|
case 'ObjectId':
|
|
299
|
-
|
|
306
|
+
if (options.allowExpandedRefs) {
|
|
307
|
+
return REFERENCE_SCHEMA;
|
|
308
|
+
} else {
|
|
309
|
+
return OBJECT_ID_SCHEMA;
|
|
310
|
+
}
|
|
300
311
|
default:
|
|
301
312
|
throw new TypeError(`Unknown schema type ${type}`);
|
|
302
313
|
}
|
|
@@ -315,19 +326,19 @@ function getSearchSchema(schema, type) {
|
|
|
315
326
|
} else if (type === 'Date') {
|
|
316
327
|
return _yada.default.allow(schema, _yada.default.array(schema), _yada.default.object({
|
|
317
328
|
lt: _yada.default.date().iso().tag({
|
|
318
|
-
|
|
329
|
+
...DATE_TAGS,
|
|
319
330
|
description: 'Select dates occurring before.'
|
|
320
331
|
}),
|
|
321
332
|
gt: _yada.default.date().iso().tag({
|
|
322
|
-
|
|
333
|
+
...DATE_TAGS,
|
|
323
334
|
description: 'Select dates occurring after.'
|
|
324
335
|
}),
|
|
325
336
|
lte: _yada.default.date().iso().tag({
|
|
326
|
-
|
|
337
|
+
...DATE_TAGS,
|
|
327
338
|
description: 'Select dates occurring on or before.'
|
|
328
339
|
}),
|
|
329
340
|
gte: _yada.default.date().iso().tag({
|
|
330
|
-
|
|
341
|
+
...DATE_TAGS,
|
|
331
342
|
description: 'Select dates occurring on or after.'
|
|
332
343
|
})
|
|
333
344
|
}).tag({
|
package/package.json
CHANGED
package/src/search.js
CHANGED
|
@@ -119,11 +119,13 @@ function validateDefinition(definition) {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
function resolveSort(sort, schema) {
|
|
122
|
-
if (!
|
|
122
|
+
if (!sort) {
|
|
123
|
+
sort = [];
|
|
124
|
+
} else if (!Array.isArray(sort)) {
|
|
123
125
|
sort = [sort];
|
|
124
126
|
}
|
|
125
127
|
for (let { field } of sort) {
|
|
126
|
-
if (!schema.path(field)) {
|
|
128
|
+
if (!field || !schema.path(field)) {
|
|
127
129
|
throw new Error(`Unknown sort field "${field}".`);
|
|
128
130
|
}
|
|
129
131
|
}
|
package/src/validation.js
CHANGED
|
@@ -10,27 +10,35 @@ import { hasUniqueConstraints, assertUnique } from './soft-delete';
|
|
|
10
10
|
import { isMongooseSchema, isSchemaTypedef } from './utils';
|
|
11
11
|
import { INCLUDE_FIELD_SCHEMA } from './include';
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const DATE_TAGS = {
|
|
14
14
|
'x-schema': 'DateTime',
|
|
15
15
|
'x-description':
|
|
16
16
|
'A `string` in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const OBJECT_ID_SCHEMA = yd.string().mongo().tag({
|
|
20
|
+
'x-schema': 'ObjectId',
|
|
21
|
+
'x-description':
|
|
22
|
+
'A 24 character hexadecimal string representing a Mongo [ObjectId](https://bit.ly/3YPtGlU).',
|
|
17
23
|
});
|
|
18
24
|
|
|
19
|
-
const
|
|
25
|
+
const REFERENCE_SCHEMA = yd
|
|
26
|
+
.allow(
|
|
27
|
+
OBJECT_ID_SCHEMA,
|
|
28
|
+
yd
|
|
29
|
+
.object({
|
|
30
|
+
id: OBJECT_ID_SCHEMA.required(),
|
|
31
|
+
})
|
|
32
|
+
.custom((obj) => {
|
|
33
|
+
return obj.id;
|
|
34
|
+
})
|
|
35
|
+
)
|
|
36
|
+
.tag({
|
|
37
|
+
'x-schema': 'Reference',
|
|
38
|
+
'x-description': `
|
|
20
39
|
A 24 character hexadecimal string representing a Mongo [ObjectId](https://bit.ly/3YPtGlU).
|
|
21
40
|
An object with an \`id\` field may also be passed, which will be converted into a string.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export const OBJECT_ID_SCHEMA = yd
|
|
25
|
-
.custom(async (val) => {
|
|
26
|
-
const id = String(val.id || val);
|
|
27
|
-
await namedSchemas.objectId.validate(id);
|
|
28
|
-
return id;
|
|
29
|
-
})
|
|
30
|
-
.tag({
|
|
31
|
-
type: 'ObjectId',
|
|
32
|
-
'x-schema': 'ObjectId',
|
|
33
|
-
'x-description': OBJECT_ID_DESCRIPTION.trim(),
|
|
41
|
+
`.trim(),
|
|
34
42
|
});
|
|
35
43
|
|
|
36
44
|
const namedSchemas = {
|
|
@@ -39,7 +47,7 @@ const namedSchemas = {
|
|
|
39
47
|
email: yd.string().lowercase().email(),
|
|
40
48
|
// Force "objectId" to have parity with refs.
|
|
41
49
|
// "mongo" is notably excluded here for this reason.
|
|
42
|
-
objectId:
|
|
50
|
+
objectId: OBJECT_ID_SCHEMA,
|
|
43
51
|
|
|
44
52
|
ascii: yd.string().ascii(),
|
|
45
53
|
base64: yd.string().base64(),
|
|
@@ -79,6 +87,7 @@ export function applyValidation(schema, definition) {
|
|
|
79
87
|
allowIncludes: true,
|
|
80
88
|
stripDeleted: true,
|
|
81
89
|
stripTimestamps: true,
|
|
90
|
+
allowExpandedRefs: true,
|
|
82
91
|
requireWriteAccess: true,
|
|
83
92
|
...(hasUnique && {
|
|
84
93
|
assertUniqueOptions: {
|
|
@@ -100,6 +109,7 @@ export function applyValidation(schema, definition) {
|
|
|
100
109
|
stripUnknown: true,
|
|
101
110
|
stripDeleted: true,
|
|
102
111
|
stripTimestamps: true,
|
|
112
|
+
allowExpandedRefs: true,
|
|
103
113
|
requireWriteAccess: true,
|
|
104
114
|
...(hasUnique && {
|
|
105
115
|
assertUniqueOptions: {
|
|
@@ -216,7 +226,7 @@ function getObjectSchema(arg, options) {
|
|
|
216
226
|
|
|
217
227
|
return schema;
|
|
218
228
|
} else {
|
|
219
|
-
return getSchemaForType(arg);
|
|
229
|
+
return getSchemaForType(arg, options);
|
|
220
230
|
}
|
|
221
231
|
}
|
|
222
232
|
|
|
@@ -252,12 +262,15 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
252
262
|
} else if (typeof type === 'object') {
|
|
253
263
|
schema = getObjectSchema(type, options);
|
|
254
264
|
} else {
|
|
255
|
-
schema = getSchemaForType(type);
|
|
265
|
+
schema = getSchemaForType(type, options);
|
|
256
266
|
}
|
|
257
267
|
|
|
258
268
|
if (isRequired(typedef, options)) {
|
|
259
269
|
schema = schema.required();
|
|
260
270
|
}
|
|
271
|
+
if (typedef.default) {
|
|
272
|
+
schema = schema.default(typedef.default);
|
|
273
|
+
}
|
|
261
274
|
if (typedef.validate?.schema) {
|
|
262
275
|
schema = schema.append(typedef.validate.schema);
|
|
263
276
|
} else if (typeof typedef.validate === 'function') {
|
|
@@ -288,7 +301,7 @@ function getSchemaForTypedef(typedef, options = {}) {
|
|
|
288
301
|
return schema;
|
|
289
302
|
}
|
|
290
303
|
|
|
291
|
-
function getSchemaForType(type) {
|
|
304
|
+
function getSchemaForType(type, options) {
|
|
292
305
|
switch (type) {
|
|
293
306
|
case 'String':
|
|
294
307
|
return yd.string();
|
|
@@ -297,14 +310,18 @@ function getSchemaForType(type) {
|
|
|
297
310
|
case 'Boolean':
|
|
298
311
|
return yd.boolean();
|
|
299
312
|
case 'Date':
|
|
300
|
-
return
|
|
313
|
+
return yd.date().iso().tag(DATE_TAGS);
|
|
301
314
|
case 'Mixed':
|
|
302
315
|
case 'Object':
|
|
303
316
|
return yd.object();
|
|
304
317
|
case 'Array':
|
|
305
318
|
return yd.array();
|
|
306
319
|
case 'ObjectId':
|
|
307
|
-
|
|
320
|
+
if (options.allowExpandedRefs) {
|
|
321
|
+
return REFERENCE_SCHEMA;
|
|
322
|
+
} else {
|
|
323
|
+
return OBJECT_ID_SCHEMA;
|
|
324
|
+
}
|
|
308
325
|
default:
|
|
309
326
|
throw new TypeError(`Unknown schema type ${type}`);
|
|
310
327
|
}
|
|
@@ -341,22 +358,34 @@ function getSearchSchema(schema, type) {
|
|
|
341
358
|
yd.array(schema),
|
|
342
359
|
yd
|
|
343
360
|
.object({
|
|
344
|
-
lt: yd
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
361
|
+
lt: yd
|
|
362
|
+
.date()
|
|
363
|
+
.iso()
|
|
364
|
+
.tag({
|
|
365
|
+
...DATE_TAGS,
|
|
366
|
+
description: 'Select dates occurring before.',
|
|
367
|
+
}),
|
|
368
|
+
gt: yd
|
|
369
|
+
.date()
|
|
370
|
+
.iso()
|
|
371
|
+
.tag({
|
|
372
|
+
...DATE_TAGS,
|
|
373
|
+
description: 'Select dates occurring after.',
|
|
374
|
+
}),
|
|
375
|
+
lte: yd
|
|
376
|
+
.date()
|
|
377
|
+
.iso()
|
|
378
|
+
.tag({
|
|
379
|
+
...DATE_TAGS,
|
|
380
|
+
description: 'Select dates occurring on or before.',
|
|
381
|
+
}),
|
|
382
|
+
gte: yd
|
|
383
|
+
.date()
|
|
384
|
+
.iso()
|
|
385
|
+
.tag({
|
|
386
|
+
...DATE_TAGS,
|
|
387
|
+
description: 'Select dates occurring on or after.',
|
|
388
|
+
}),
|
|
360
389
|
})
|
|
361
390
|
.tag({
|
|
362
391
|
'x-schema': 'DateRange',
|
package/types/validation.d.ts
CHANGED
|
@@ -9,5 +9,95 @@ export function getTupleValidator(types: any): {
|
|
|
9
9
|
(val: any): Promise<void>;
|
|
10
10
|
schema: any;
|
|
11
11
|
};
|
|
12
|
-
export const OBJECT_ID_SCHEMA:
|
|
12
|
+
export const OBJECT_ID_SCHEMA: {
|
|
13
|
+
length(length: number): any;
|
|
14
|
+
min(length: number): any;
|
|
15
|
+
max(length: number): any;
|
|
16
|
+
trim(): any;
|
|
17
|
+
lowercase(assert?: boolean): any;
|
|
18
|
+
uppercase(assert?: boolean): any;
|
|
19
|
+
match(reg: RegExp): any;
|
|
20
|
+
email(): any;
|
|
21
|
+
phone(): any;
|
|
22
|
+
hex(): any;
|
|
23
|
+
md5(): any;
|
|
24
|
+
sha1(): any;
|
|
25
|
+
ascii(): any;
|
|
26
|
+
base64(options?: {
|
|
27
|
+
urlSafe?: boolean;
|
|
28
|
+
}): any;
|
|
29
|
+
creditCard(): any;
|
|
30
|
+
ip(): any;
|
|
31
|
+
country(): any;
|
|
32
|
+
locale(): any;
|
|
33
|
+
jwt(): any;
|
|
34
|
+
slug(): any;
|
|
35
|
+
latlng(): any;
|
|
36
|
+
postalCode(locale?: string): any;
|
|
37
|
+
password(options?: {
|
|
38
|
+
minLength?: number;
|
|
39
|
+
minNumbers?: number;
|
|
40
|
+
minSymbols?: number;
|
|
41
|
+
minLowercase?: number;
|
|
42
|
+
minUppercase?: number;
|
|
43
|
+
}): any;
|
|
44
|
+
url(options?: {
|
|
45
|
+
require_protocol?: boolean;
|
|
46
|
+
require_valid_protocol?: boolean;
|
|
47
|
+
require_host?: boolean;
|
|
48
|
+
require_port?: boolean;
|
|
49
|
+
allow_protocol_relative_urls?: boolean;
|
|
50
|
+
allow_fragments?: boolean;
|
|
51
|
+
allow_query_components?: boolean;
|
|
52
|
+
validate_length?: boolean;
|
|
53
|
+
protocols?: string[];
|
|
54
|
+
}): any;
|
|
55
|
+
domain(options?: {
|
|
56
|
+
require_tld?: boolean;
|
|
57
|
+
allow_underscores?: boolean;
|
|
58
|
+
allow_trailing_dot?: boolean;
|
|
59
|
+
allow_numeric_tld?: boolean;
|
|
60
|
+
allow_wildcard?: boolean;
|
|
61
|
+
ignore_max_length?: boolean;
|
|
62
|
+
}): any;
|
|
63
|
+
uuid(version?: 1 | 2 | 5 | 3 | 4): any;
|
|
64
|
+
btc(): any;
|
|
65
|
+
eth(): any;
|
|
66
|
+
swift(): any;
|
|
67
|
+
mongo(): any;
|
|
68
|
+
format(name: any, fn: any): import("@bedrockio/yada/types/TypeSchema").default;
|
|
69
|
+
toString(): any;
|
|
70
|
+
assertions: any[];
|
|
71
|
+
meta: {};
|
|
72
|
+
required(): any;
|
|
73
|
+
default(value: any): any;
|
|
74
|
+
custom(...args: import("@bedrockio/yada/types/Schema").CustomSignature): any;
|
|
75
|
+
strip(strip: any): any;
|
|
76
|
+
allow(...set: any[]): any;
|
|
77
|
+
reject(...set: any[]): any;
|
|
78
|
+
message(message: any): any;
|
|
79
|
+
tag(tags: any): any;
|
|
80
|
+
description(description: any): any;
|
|
81
|
+
options(options: any): any;
|
|
82
|
+
validate(value: any, options?: {}): Promise<any>;
|
|
83
|
+
clone(meta: any): any;
|
|
84
|
+
append(schema: any): any;
|
|
85
|
+
toOpenApi(extra: any): any;
|
|
86
|
+
expandExtra(extra?: {}): {};
|
|
87
|
+
assertEnum(set: any, allow: any): any;
|
|
88
|
+
assert(type: any, fn: any): any;
|
|
89
|
+
pushAssertion(assertion: any): void;
|
|
90
|
+
transform(fn: any): any;
|
|
91
|
+
getSortIndex(type: any): number;
|
|
92
|
+
runAssertion(assertion: any, value: any, options?: {}): Promise<any>;
|
|
93
|
+
enumToOpenApi(): {
|
|
94
|
+
type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
|
|
95
|
+
enum: any;
|
|
96
|
+
oneOf?: undefined;
|
|
97
|
+
} | {
|
|
98
|
+
oneOf: any[];
|
|
99
|
+
type?: undefined;
|
|
100
|
+
enum?: undefined;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
13
103
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.js"],"names":[],"mappings":"AAyEA,kDAEC;AAED,oEA8EC;AAsBD,wEAkBC;AA6QD;;;EAEC;AAED;;;EAOC;AAzcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIG"}
|