vrack2-core 1.0.3 → 1.0.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 +15 -4
- package/lib/Container.js +3 -1
- package/lib/errors/ErrorManager.d.ts +12 -0
- package/lib/errors/ErrorManager.js +34 -3
- package/lib/service/Device.d.ts +11 -0
- package/lib/service/Device.js +10 -2
- package/lib/service/DevicePort.d.ts +1 -0
- package/lib/service/DevicePort.js +5 -0
- package/lib/validator/types/BasicType.d.ts +6 -0
- package/lib/validator/types/BasicType.js +9 -0
- package/package.json +1 -1
- package/src/Container.ts +6 -1
- package/src/errors/ErrorManager.ts +32 -2
- package/src/service/Device.ts +19 -2
- package/src/service/DevicePort.ts +5 -0
- package/src/validator/types/BasicType.ts +10 -0
package/README.md
CHANGED
|
@@ -9,10 +9,21 @@ VRack2 Core
|
|
|
9
9
|
|
|
10
10
|
--------
|
|
11
11
|
|
|
12
|
-
### Последнее
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
12
|
+
### Последнее обновление 1.0.5
|
|
13
|
+
- В Container добавлена ошибка `CTR_IGNORE_SERVICE_AUTORELOAD` её можно использовать, когда не хочется что бы после завершения работы сервиса - сервис автоматически перезапускался
|
|
14
|
+
- В класс `Device` добавлены
|
|
15
|
+
- Свойство `works: boolean = true` - если `false` - устройство перестает принимать и отправлять данные через порты
|
|
16
|
+
- Метод `beforeTerminate(){ return }` - может вызываться перед завершением сервиса (зависит от реализации)
|
|
17
|
+
- Теперь бинд входящего порта осуществляется по другому. Теперь вместо замены `DevicePort.push` ссылка на хендлер складывается в `DevicePort.bind` и уже после этого происходит вызов `DevicePort.bind()` внутри `DevicePort.push`
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Последнее обновление 1.0.4
|
|
21
|
+
|
|
22
|
+
- `BasicType` (класс `Rule`) `require()` deprecated - используем `required()`
|
|
23
|
+
- **ErrorManager** - Теперь не создаёт ошибку при повторной регистрации с одинаковыми параметрами
|
|
24
|
+
- Добавлены методы в **ErrorManager**
|
|
25
|
+
- isCode(error: any, code: string) - Проверяет является ли ошибка VRack2 Error и соответсвует ли код переданной ошибке (проверяет vShort и vCode)
|
|
26
|
+
- isError(error: any) - Проверяет - пренадлежит ли объект ошибки CoreError
|
|
16
27
|
|
|
17
28
|
**Использовать эту документацию имеет смысл только для более глубокого изучения устройства VRack2 или для создания сервиса независимого от VRack2**
|
|
18
29
|
|
package/lib/Container.js
CHANGED
|
@@ -85,6 +85,7 @@ ErrorManager_1.default.register('Container', 'XR1K10R0OOUC', 'CTR_INCOMPATIBLE_P
|
|
|
85
85
|
});
|
|
86
86
|
ErrorManager_1.default.register('Container', 'MmVoDOQwaYkx', 'CTR_INCORRECT_BOOSTRAP', 'The required DeviceManager class is not specified correctly', {});
|
|
87
87
|
ErrorManager_1.default.register('Container', 'e090R0MLyb7y', 'CTR_CONF_EXTENDS_PROBLEM', 'Problem with extending service configuration.', {});
|
|
88
|
+
ErrorManager_1.default.register('Container', 'LYC0VA1AWYKU', 'CTR_IGNORE_SERVICE_AUTORELOAD', 'Error that ignores service restart flag', {});
|
|
88
89
|
/**
|
|
89
90
|
* Service Load Class. It loads all devices in the list,
|
|
90
91
|
* establishes connections between them, and performs device startup.
|
|
@@ -373,8 +374,9 @@ class Container extends events_1.default {
|
|
|
373
374
|
// add structure device input ports
|
|
374
375
|
this.structure[dconf.id].inputs[subkey] = [];
|
|
375
376
|
this.structure[dconf.id].ports.push(Object.assign({ port: subkey, direct: 'input' }, pList[subkey]));
|
|
377
|
+
// биндимся а не заменяем push для контроля внутри push
|
|
376
378
|
if (handler in dev)
|
|
377
|
-
ndp.
|
|
379
|
+
ndp.bind = dev[handler].bind(dev);
|
|
378
380
|
}
|
|
379
381
|
}
|
|
380
382
|
// make output ports
|
|
@@ -34,6 +34,18 @@ declare class ErrorManager {
|
|
|
34
34
|
* @param error Ошибка для преобразования
|
|
35
35
|
*/
|
|
36
36
|
convert(error: any): any;
|
|
37
|
+
/**
|
|
38
|
+
* Проверяет является ли ошибка VRack2 Error
|
|
39
|
+
* и соответсвует ли код переданной ошибке (проверяет vShort и vCode)
|
|
40
|
+
*/
|
|
41
|
+
isCode(error: any, code: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Проверяет - пренадлежит объект ошибки VRack2 Error
|
|
44
|
+
*
|
|
45
|
+
* Это не обязательно должен быть класс CoreError но и
|
|
46
|
+
* любой сериализированный класс ошибки VRack2
|
|
47
|
+
*/
|
|
48
|
+
isError(error: any): boolean;
|
|
37
49
|
/**
|
|
38
50
|
* Searches for an error by code or short
|
|
39
51
|
*
|
|
@@ -31,8 +31,15 @@ class ErrorManager {
|
|
|
31
31
|
register(name, code, short, description, rules = {}) {
|
|
32
32
|
const reg1 = this.getRegistered(code);
|
|
33
33
|
const reg2 = this.getRegistered(short);
|
|
34
|
-
if (reg1 !== null || reg2 !== null)
|
|
35
|
-
|
|
34
|
+
if (reg1 !== null || reg2 !== null) {
|
|
35
|
+
// Если уже есть идентичная запись - просто игнорим
|
|
36
|
+
if ((reg1 === null || reg1 === void 0 ? void 0 : reg1.code) === (reg2 === null || reg2 === void 0 ? void 0 : reg2.code) && (reg1 === null || reg1 === void 0 ? void 0 : reg1.short) === (reg2 === null || reg2 === void 0 ? void 0 : reg2.short)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
throw this.make('EM_CODE_EXISTS', { code, short });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
36
43
|
const nr = { name, code, short, description, rules };
|
|
37
44
|
this.registeredList.push(nr);
|
|
38
45
|
}
|
|
@@ -66,6 +73,30 @@ class ErrorManager {
|
|
|
66
73
|
ne.import(error);
|
|
67
74
|
return ne;
|
|
68
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Проверяет является ли ошибка VRack2 Error
|
|
78
|
+
* и соответсвует ли код переданной ошибке (проверяет vShort и vCode)
|
|
79
|
+
*/
|
|
80
|
+
isCode(error, code) {
|
|
81
|
+
if (!this.isError(error))
|
|
82
|
+
return false;
|
|
83
|
+
if (error.vShort === code || error.vCode === code)
|
|
84
|
+
return true;
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Проверяет - пренадлежит объект ошибки VRack2 Error
|
|
89
|
+
*
|
|
90
|
+
* Это не обязательно должен быть класс CoreError но и
|
|
91
|
+
* любой сериализированный класс ошибки VRack2
|
|
92
|
+
*/
|
|
93
|
+
isError(error) {
|
|
94
|
+
if (error instanceof CoreError_1.default)
|
|
95
|
+
return true;
|
|
96
|
+
if (error.vError && error.vCode !== undefined && error.vShort !== undefined)
|
|
97
|
+
return true;
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
69
100
|
/**
|
|
70
101
|
* Searches for an error by code or short
|
|
71
102
|
*
|
|
@@ -79,7 +110,7 @@ class ErrorManager {
|
|
|
79
110
|
}
|
|
80
111
|
}
|
|
81
112
|
const GlobalErrorManager = new ErrorManager();
|
|
82
|
-
GlobalErrorManager.register('ErrorManager', 'NcZIb9QvQRcq', 'EM_CODE_EXISTS', '
|
|
113
|
+
GlobalErrorManager.register('ErrorManager', 'NcZIb9QvQRcq', 'EM_CODE_EXISTS', 'Has anyone else encountered this error code? Possible duplication of the error code and short word in different registrations.');
|
|
83
114
|
GlobalErrorManager.register('ErrorManager', 'uLYv4mE1Yo50', 'EM_CODE_NOT_FOUND', 'No such error found');
|
|
84
115
|
GlobalErrorManager.register('ErrorManager', 'RIl3BUrxWOzP', 'EM_ERROR_CONVERT', 'Converted error');
|
|
85
116
|
exports.default = GlobalErrorManager;
|
package/lib/service/Device.d.ts
CHANGED
|
@@ -40,6 +40,12 @@ export default class Device {
|
|
|
40
40
|
* @example 'vrack.KeyManager'
|
|
41
41
|
*/
|
|
42
42
|
type: string;
|
|
43
|
+
/**
|
|
44
|
+
* Флаг общей работы
|
|
45
|
+
* Если флаг === false = все порты перестают принимать или отправлять данные/события
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
works: boolean;
|
|
43
49
|
/**
|
|
44
50
|
* Allows access to port management.
|
|
45
51
|
*/
|
|
@@ -136,6 +142,11 @@ export default class Device {
|
|
|
136
142
|
* @param data data for action
|
|
137
143
|
*/
|
|
138
144
|
beforeAction(action: string, data: any): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Должен вызываться перед завершением сервиса
|
|
147
|
+
* Но может не вызываться (зависит от реализации)
|
|
148
|
+
*/
|
|
149
|
+
beforeTerminate(): void;
|
|
139
150
|
/**
|
|
140
151
|
* Prepare options
|
|
141
152
|
*
|
package/lib/service/Device.js
CHANGED
|
@@ -58,6 +58,7 @@ class Device {
|
|
|
58
58
|
this.id = id;
|
|
59
59
|
this.type = type;
|
|
60
60
|
this.Container = Container;
|
|
61
|
+
this.works = true;
|
|
61
62
|
this.ports = {
|
|
62
63
|
input: {},
|
|
63
64
|
output: {}
|
|
@@ -118,6 +119,11 @@ class Device {
|
|
|
118
119
|
* @param data data for action
|
|
119
120
|
*/
|
|
120
121
|
beforeAction(action, data) { return true; }
|
|
122
|
+
/**
|
|
123
|
+
* Должен вызываться перед завершением сервиса
|
|
124
|
+
* Но может не вызываться (зависит от реализации)
|
|
125
|
+
*/
|
|
126
|
+
beforeTerminate() { return; }
|
|
121
127
|
/**
|
|
122
128
|
* Prepare options
|
|
123
129
|
*
|
|
@@ -268,7 +274,8 @@ class Device {
|
|
|
268
274
|
*/
|
|
269
275
|
addInputHandler(name, action) {
|
|
270
276
|
name = ImportManager_1.default.camelize('input.' + name);
|
|
271
|
-
|
|
277
|
+
const a = this;
|
|
278
|
+
a[name] = action;
|
|
272
279
|
}
|
|
273
280
|
/**
|
|
274
281
|
* Adding a handle for the action
|
|
@@ -278,7 +285,8 @@ class Device {
|
|
|
278
285
|
*/
|
|
279
286
|
addActionHandler(name, action) {
|
|
280
287
|
name = ImportManager_1.default.camelize('action.' + name);
|
|
281
|
-
|
|
288
|
+
const a = this;
|
|
289
|
+
a[name] = action;
|
|
282
290
|
}
|
|
283
291
|
/**
|
|
284
292
|
* Informs the rack that the unit cannot continue to operate.
|
|
@@ -18,6 +18,7 @@ export default class DevicePort {
|
|
|
18
18
|
required: boolean;
|
|
19
19
|
/** Ссылка на устройсто владельца */
|
|
20
20
|
Device: Device;
|
|
21
|
+
bind: ((data: any) => {}) | null;
|
|
21
22
|
/**
|
|
22
23
|
* Список слушателей порта
|
|
23
24
|
* Используется для захвата порта. Если какие либо данные будут проброшены
|
|
@@ -18,6 +18,7 @@ class DevicePort {
|
|
|
18
18
|
this.connected = false;
|
|
19
19
|
/** Port connection list. One port can have multiple connections */
|
|
20
20
|
this.connections = [];
|
|
21
|
+
this.bind = null;
|
|
21
22
|
/**
|
|
22
23
|
* Список слушателей порта
|
|
23
24
|
* Используется для захвата порта. Если какие либо данные будут проброшены
|
|
@@ -40,6 +41,10 @@ class DevicePort {
|
|
|
40
41
|
* Calling the incoming port when calling a connection
|
|
41
42
|
*/
|
|
42
43
|
push(data) {
|
|
44
|
+
if (!this.Device.works)
|
|
45
|
+
return;
|
|
46
|
+
if (this.bind !== null)
|
|
47
|
+
return this.bind(data);
|
|
43
48
|
// Если у нас есть слушатели порта
|
|
44
49
|
// Передаем им данные и пересоздаем Map
|
|
45
50
|
if (this.listens.size) {
|
|
@@ -2,6 +2,12 @@ import IValidationRule from "../IValidationRule";
|
|
|
2
2
|
export default class BasicType {
|
|
3
3
|
protected rule: IValidationRule;
|
|
4
4
|
constructor();
|
|
5
|
+
required(): this;
|
|
6
|
+
/**
|
|
7
|
+
* Вскоре будет удален
|
|
8
|
+
* @see required
|
|
9
|
+
* @deprecated use required()
|
|
10
|
+
*/
|
|
5
11
|
require(): this;
|
|
6
12
|
/**
|
|
7
13
|
* Example of a valid value for this rule
|
|
@@ -20,6 +20,15 @@ class BasicType {
|
|
|
20
20
|
message: '',
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
required() {
|
|
24
|
+
this.rule.require = true;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Вскоре будет удален
|
|
29
|
+
* @see required
|
|
30
|
+
* @deprecated use required()
|
|
31
|
+
*/
|
|
23
32
|
require() {
|
|
24
33
|
this.rule.require = true;
|
|
25
34
|
return this;
|
package/package.json
CHANGED
package/src/Container.ts
CHANGED
|
@@ -107,6 +107,9 @@ ErrorManager.register('Container', 'XR1K10R0OOUC', 'CTR_INCOMPATIBLE_PORTS', 'In
|
|
|
107
107
|
ErrorManager.register('Container', 'MmVoDOQwaYkx', 'CTR_INCORRECT_BOOSTRAP', 'The required DeviceManager class is not specified correctly', {})
|
|
108
108
|
ErrorManager.register('Container', 'e090R0MLyb7y', 'CTR_CONF_EXTENDS_PROBLEM', 'Problem with extending service configuration.', {})
|
|
109
109
|
|
|
110
|
+
ErrorManager.register('Container', 'LYC0VA1AWYKU', 'CTR_IGNORE_SERVICE_AUTORELOAD', 'Error that ignores service restart flag', {})
|
|
111
|
+
|
|
112
|
+
|
|
110
113
|
|
|
111
114
|
/**
|
|
112
115
|
* Contains the structure of the service
|
|
@@ -474,7 +477,9 @@ export default class Container extends EventEmitter {
|
|
|
474
477
|
this.structure[dconf.id].ports.push(
|
|
475
478
|
Object.assign({ port: subkey, direct: 'input' }, pList[subkey])
|
|
476
479
|
)
|
|
477
|
-
|
|
480
|
+
|
|
481
|
+
// биндимся а не заменяем push для контроля внутри push
|
|
482
|
+
if (handler in dev) ndp.bind = dev[handler].bind(dev)
|
|
478
483
|
}
|
|
479
484
|
}
|
|
480
485
|
|
|
@@ -49,7 +49,14 @@ class ErrorManager {
|
|
|
49
49
|
register(name: string, code: string, short: string, description: string, rules: { [key: string]: BasicType } = {}) {
|
|
50
50
|
const reg1 = this.getRegistered(code)
|
|
51
51
|
const reg2 = this.getRegistered(short)
|
|
52
|
-
if (reg1 !== null || reg2 !== null)
|
|
52
|
+
if (reg1 !== null || reg2 !== null) {
|
|
53
|
+
// Если уже есть идентичная запись - просто игнорим
|
|
54
|
+
if (reg1?.code === reg2?.code && reg1?.short === reg2?.short){
|
|
55
|
+
return
|
|
56
|
+
}else {
|
|
57
|
+
throw this.make('EM_CODE_EXISTS', { code, short })
|
|
58
|
+
}
|
|
59
|
+
}
|
|
53
60
|
const nr = { name, code, short, description, rules }
|
|
54
61
|
this.registeredList.push(nr)
|
|
55
62
|
}
|
|
@@ -74,6 +81,7 @@ class ErrorManager {
|
|
|
74
81
|
return Object.assign(ne, additional)
|
|
75
82
|
}
|
|
76
83
|
|
|
84
|
+
|
|
77
85
|
/**
|
|
78
86
|
* Converts a normal error to a VRack error
|
|
79
87
|
*
|
|
@@ -86,6 +94,28 @@ class ErrorManager {
|
|
|
86
94
|
return ne
|
|
87
95
|
}
|
|
88
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Проверяет является ли ошибка VRack2 Error
|
|
99
|
+
* и соответсвует ли код переданной ошибке (проверяет vShort и vCode)
|
|
100
|
+
*/
|
|
101
|
+
isCode(error: any, code: string){
|
|
102
|
+
if (!this.isError(error)) return false
|
|
103
|
+
if (error.vShort === code || error.vCode === code) return true
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Проверяет - пренадлежит объект ошибки VRack2 Error
|
|
109
|
+
*
|
|
110
|
+
* Это не обязательно должен быть класс CoreError но и
|
|
111
|
+
* любой сериализированный класс ошибки VRack2
|
|
112
|
+
*/
|
|
113
|
+
isError(error: any){
|
|
114
|
+
if (error instanceof CoreError) return true
|
|
115
|
+
if (error.vError && error.vCode !== undefined && error.vShort !== undefined) return true
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
|
|
89
119
|
/**
|
|
90
120
|
* Searches for an error by code or short
|
|
91
121
|
*
|
|
@@ -100,7 +130,7 @@ class ErrorManager {
|
|
|
100
130
|
|
|
101
131
|
|
|
102
132
|
const GlobalErrorManager = new ErrorManager()
|
|
103
|
-
GlobalErrorManager.register('ErrorManager', 'NcZIb9QvQRcq', 'EM_CODE_EXISTS', '
|
|
133
|
+
GlobalErrorManager.register('ErrorManager', 'NcZIb9QvQRcq', 'EM_CODE_EXISTS', 'Has anyone else encountered this error code? Possible duplication of the error code and short word in different registrations.')
|
|
104
134
|
GlobalErrorManager.register('ErrorManager', 'uLYv4mE1Yo50', 'EM_CODE_NOT_FOUND', 'No such error found')
|
|
105
135
|
GlobalErrorManager.register('ErrorManager', 'RIl3BUrxWOzP', 'EM_ERROR_CONVERT', 'Converted error')
|
|
106
136
|
export default GlobalErrorManager
|
package/src/service/Device.ts
CHANGED
|
@@ -54,6 +54,13 @@ export default class Device {
|
|
|
54
54
|
*/
|
|
55
55
|
type: string;
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Флаг общей работы
|
|
59
|
+
* Если флаг === false = все порты перестают принимать или отправлять данные/события
|
|
60
|
+
*
|
|
61
|
+
*/
|
|
62
|
+
works: boolean
|
|
63
|
+
|
|
57
64
|
/**
|
|
58
65
|
* Allows access to port management.
|
|
59
66
|
*/
|
|
@@ -83,6 +90,7 @@ export default class Device {
|
|
|
83
90
|
this.id = id
|
|
84
91
|
this.type = type
|
|
85
92
|
this.Container = Container
|
|
93
|
+
this.works = true
|
|
86
94
|
this.ports = {
|
|
87
95
|
input: {},
|
|
88
96
|
output: {}
|
|
@@ -165,6 +173,12 @@ export default class Device {
|
|
|
165
173
|
* @param data data for action
|
|
166
174
|
*/
|
|
167
175
|
beforeAction(action: string, data: any) { return true }
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Должен вызываться перед завершением сервиса
|
|
179
|
+
* Но может не вызываться (зависит от реализации)
|
|
180
|
+
*/
|
|
181
|
+
beforeTerminate(){ return }
|
|
168
182
|
|
|
169
183
|
/**
|
|
170
184
|
* Prepare options
|
|
@@ -330,7 +344,8 @@ export default class Device {
|
|
|
330
344
|
*/
|
|
331
345
|
addInputHandler(name: string, action: (data: any) => any) {
|
|
332
346
|
name = ImportManager.camelize('input.' + name)
|
|
333
|
-
|
|
347
|
+
const a = this as any
|
|
348
|
+
a[name] = action
|
|
334
349
|
}
|
|
335
350
|
|
|
336
351
|
/**
|
|
@@ -341,7 +356,8 @@ export default class Device {
|
|
|
341
356
|
*/
|
|
342
357
|
addActionHandler(name: string, action: (data: any) => any) {
|
|
343
358
|
name = ImportManager.camelize('action.' + name)
|
|
344
|
-
|
|
359
|
+
const a = this as any
|
|
360
|
+
a[name] = action
|
|
345
361
|
}
|
|
346
362
|
|
|
347
363
|
/**
|
|
@@ -353,4 +369,5 @@ export default class Device {
|
|
|
353
369
|
terminate(error: Error, action: string) {
|
|
354
370
|
return this.makeEvent('device.terminate', action, error, [])
|
|
355
371
|
}
|
|
372
|
+
|
|
356
373
|
}
|
|
@@ -30,6 +30,8 @@ export default class DevicePort {
|
|
|
30
30
|
/** Ссылка на устройсто владельца */
|
|
31
31
|
Device: Device
|
|
32
32
|
|
|
33
|
+
bind: ((data: any) => {}) | null = null;
|
|
34
|
+
|
|
33
35
|
/**
|
|
34
36
|
* Список слушателей порта
|
|
35
37
|
* Используется для захвата порта. Если какие либо данные будут проброшены
|
|
@@ -56,6 +58,9 @@ export default class DevicePort {
|
|
|
56
58
|
* Calling the incoming port when calling a connection
|
|
57
59
|
*/
|
|
58
60
|
push(data: any): any {
|
|
61
|
+
if (!this.Device.works) return
|
|
62
|
+
if (this.bind !== null) return this.bind(data)
|
|
63
|
+
|
|
59
64
|
// Если у нас есть слушатели порта
|
|
60
65
|
// Передаем им данные и пересоздаем Map
|
|
61
66
|
if (this.listens.size) {
|
|
@@ -21,6 +21,16 @@ export default class BasicType {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
required(){
|
|
25
|
+
this.rule.require = true
|
|
26
|
+
return this
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Вскоре будет удален
|
|
31
|
+
* @see required
|
|
32
|
+
* @deprecated use required()
|
|
33
|
+
*/
|
|
24
34
|
require(){
|
|
25
35
|
this.rule.require = true
|
|
26
36
|
return this
|