ee-core 2.9.2-beta.1 → 2.10.0
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/LICENSE +21 -21
- package/README.md +65 -65
- package/addon/index.js +34 -34
- package/addon/window/index.js +98 -98
- package/bin/tools.js +8 -8
- package/config/cache.js +41 -38
- package/config/config.default.js +331 -330
- package/config/index.js +75 -73
- package/const/channel.js +17 -17
- package/const/index.js +8 -8
- package/controller/baseContextClass.js +34 -34
- package/controller/index.js +34 -34
- package/core/index.js +10 -10
- package/core/lib/ee.js +216 -216
- package/core/lib/loader/context_loader.js +106 -106
- package/core/lib/loader/ee_loader.js +435 -435
- package/core/lib/loader/file_loader.js +326 -326
- package/core/lib/loader/mixin/addon.js +32 -32
- package/core/lib/loader/mixin/config.js +130 -130
- package/core/lib/loader/mixin/controller.js +125 -125
- package/core/lib/loader/mixin/service.js +28 -28
- package/core/lib/utils/base_context_class.js +34 -34
- package/core/lib/utils/function.js +30 -30
- package/core/lib/utils/index.js +133 -133
- package/core/lib/utils/sequencify.js +59 -59
- package/core/lib/utils/timing.js +77 -77
- package/cross/index.js +183 -183
- package/cross/spawnProcess.js +183 -183
- package/ee/appLoader.js +48 -48
- package/ee/application.js +99 -99
- package/ee/baseApp.js +103 -102
- package/ee/eeApp.js +408 -408
- package/ee/index.js +57 -57
- package/electron/app/index.js +64 -58
- package/electron/index.js +19 -19
- package/electron/window/index.js +73 -73
- package/electron/window/winState.js +186 -186
- package/exception/index.js +112 -112
- package/html/boot.html +98 -98
- package/html/cross-failure.html +28 -28
- package/html/failure.html +28 -28
- package/html/index.js +13 -13
- package/httpclient/index.js +161 -161
- package/index.js +54 -54
- package/jobs/baseJobClass.js +16 -16
- package/jobs/child/app.js +65 -65
- package/jobs/child/forkProcess.js +145 -145
- package/jobs/child/index.js +82 -82
- package/jobs/child-pool/index.js +213 -213
- package/jobs/index.js +8 -8
- package/jobs/load-balancer/algorithm/index.js +11 -11
- package/jobs/load-balancer/algorithm/minimumConnection.js +18 -18
- package/jobs/load-balancer/algorithm/polling.js +11 -11
- package/jobs/load-balancer/algorithm/random.js +9 -9
- package/jobs/load-balancer/algorithm/specify.js +14 -14
- package/jobs/load-balancer/algorithm/weights.js +21 -21
- package/jobs/load-balancer/algorithm/weightsMinimumConnection.js +29 -29
- package/jobs/load-balancer/algorithm/weightsPolling.js +22 -22
- package/jobs/load-balancer/algorithm/weightsRandom.js +16 -16
- package/jobs/load-balancer/consts.js +9 -9
- package/jobs/load-balancer/index.js +201 -201
- package/jobs/load-balancer/scheduler.js +31 -31
- package/jobs/renderer/index.js +141 -141
- package/jobs/renderer/loadView.js +40 -40
- package/jobs/unification.js +63 -63
- package/loader/index.js +172 -172
- package/log/index.js +68 -68
- package/log/logger.js +86 -80
- package/main/index.js +56 -56
- package/message/childMessage.js +54 -54
- package/message/index.js +18 -18
- package/old-utils/index.js +91 -91
- package/package.json +38 -38
- package/ps/index.js +371 -371
- package/services/baseContextClass.js +34 -34
- package/services/index.js +40 -40
- package/socket/httpServer.js +147 -147
- package/socket/index.js +81 -81
- package/socket/io.js +27 -27
- package/socket/ipcServer.js +112 -112
- package/socket/socketServer.js +69 -65
- package/storage/index.js +38 -38
- package/storage/jsondb/adapters/Base.js +23 -23
- package/storage/jsondb/adapters/FileSync.js +64 -52
- package/storage/jsondb/main.js +55 -42
- package/storage/jsondbStorage.js +195 -195
- package/storage/sqliteStorage.js +123 -123
- package/utils/co.js +237 -237
- package/utils/copyto.js +160 -160
- package/utils/depd/index.js +538 -538
- package/utils/depd/lib/browser/index.js +77 -77
- package/utils/extend.js +73 -73
- package/utils/get-port/index.d.ts +64 -64
- package/utils/get-port/index.js +148 -148
- package/utils/helper.js +220 -220
- package/utils/index.js +160 -160
- package/utils/ip.js +261 -261
- package/utils/is.js +145 -145
- package/utils/json.js +72 -72
- package/utils/pargv.js +263 -263
- package/utils/time/index.js +19 -19
- package/utils/time/ms.js +162 -162
- package/utils/wrap.js +35 -35
package/utils/helper.js
CHANGED
|
@@ -1,221 +1,221 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const mkdirp = require('mkdirp');
|
|
3
|
-
const convert = require('koa-convert');
|
|
4
|
-
const is = require('is-type-of');
|
|
5
|
-
const co = require('./co');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const chalk = require('chalk');
|
|
8
|
-
const Pargv = require('./pargv');
|
|
9
|
-
|
|
10
|
-
const _basePath = process.cwd();
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* fnDebounce
|
|
14
|
-
*
|
|
15
|
-
* @param {Function} fn - 回调函数
|
|
16
|
-
* @param {Time} delayTime - 延迟时间(ms)
|
|
17
|
-
* @param {Boolean} isImediate - 是否需要立即调用
|
|
18
|
-
* @param {type} args - 回调函数传入参数
|
|
19
|
-
*/
|
|
20
|
-
exports.fnDebounce = function() {
|
|
21
|
-
const fnObject = {};
|
|
22
|
-
let timer;
|
|
23
|
-
|
|
24
|
-
return (fn, delayTime, isImediate, args) => {
|
|
25
|
-
const setTimer = () => {
|
|
26
|
-
timer = setTimeout(() => {
|
|
27
|
-
fn(args);
|
|
28
|
-
clearTimeout(timer);
|
|
29
|
-
delete fnObject[fn];
|
|
30
|
-
}, delayTime);
|
|
31
|
-
|
|
32
|
-
fnObject[fn] = { delayTime, timer };
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (!delayTime || isImediate) return fn(args);
|
|
36
|
-
|
|
37
|
-
if (fnObject[fn]) {
|
|
38
|
-
clearTimeout(timer);
|
|
39
|
-
setTimer(fn, delayTime, args);
|
|
40
|
-
} else {
|
|
41
|
-
setTimer(fn, delayTime, args);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 随机10位字符串
|
|
48
|
-
*/
|
|
49
|
-
exports.getRandomString = function() {
|
|
50
|
-
return Math.random().toString(36).substring(2);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 创建文件夹
|
|
55
|
-
*/
|
|
56
|
-
exports.mkdir = function(filepath, opt = {}) {
|
|
57
|
-
mkdirp.sync(filepath, opt);
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 修改文件权限
|
|
63
|
-
*/
|
|
64
|
-
exports.chmodPath = function(path, mode) {
|
|
65
|
-
let files = [];
|
|
66
|
-
if (fs.existsSync(path)) {
|
|
67
|
-
files = fs.readdirSync(path);
|
|
68
|
-
files.forEach((file, index) => {
|
|
69
|
-
const curPath = path + '/' + file;
|
|
70
|
-
if (fs.statSync(curPath).isDirectory()) {
|
|
71
|
-
this.chmodPath(curPath, mode); // 递归删除文件夹
|
|
72
|
-
} else {
|
|
73
|
-
fs.chmodSync(curPath, mode);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
fs.chmodSync(path, mode);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 版本号比较
|
|
82
|
-
*/
|
|
83
|
-
exports.compareVersion = function (v1, v2) {
|
|
84
|
-
v1 = v1.split('.')
|
|
85
|
-
v2 = v2.split('.')
|
|
86
|
-
const len = Math.max(v1.length, v2.length)
|
|
87
|
-
|
|
88
|
-
while (v1.length < len) {
|
|
89
|
-
v1.push('0')
|
|
90
|
-
}
|
|
91
|
-
while (v2.length < len) {
|
|
92
|
-
v2.push('0')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
for (let i = 0; i < len; i++) {
|
|
96
|
-
const num1 = parseInt(v1[i])
|
|
97
|
-
const num2 = parseInt(v2[i])
|
|
98
|
-
|
|
99
|
-
if (num1 > num2) {
|
|
100
|
-
return 1
|
|
101
|
-
} else if (num1 < num2) {
|
|
102
|
-
return -1
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return 0
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* 执行一个函数
|
|
111
|
-
*/
|
|
112
|
-
exports.callFn = async function (fn, args, ctx) {
|
|
113
|
-
args = args || [];
|
|
114
|
-
if (!is.function(fn)) return;
|
|
115
|
-
if (is.generatorFunction(fn)) fn = co.wrap(fn);
|
|
116
|
-
return ctx ? fn.call(ctx, ...args) : fn(...args);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
exports.middleware = function (fn) {
|
|
120
|
-
return is.generatorFunction(fn) ? convert(fn) : fn;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* 序列化对象
|
|
125
|
-
*/
|
|
126
|
-
exports.stringify = function(obj, ignore = []) {
|
|
127
|
-
const result = {};
|
|
128
|
-
Object.keys(obj).forEach(key => {
|
|
129
|
-
if (!ignore.includes(key)) {
|
|
130
|
-
result[key] = obj[key];
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
return JSON.stringify(result);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* 是否有效值
|
|
138
|
-
*/
|
|
139
|
-
exports.validValue = function(value) {
|
|
140
|
-
return (
|
|
141
|
-
value !== undefined &&
|
|
142
|
-
value !== null &&
|
|
143
|
-
value !== ''
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
exports.checkConfig = function(prop) {
|
|
148
|
-
const filepath = path.join(_basePath, prop);
|
|
149
|
-
if (fs.existsSync(filepath)) {
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
exports.loadConfig = function(prop) {
|
|
157
|
-
const configFile = prop;
|
|
158
|
-
const filepath = path.join(_basePath, configFile);
|
|
159
|
-
if (!fs.existsSync(filepath)) {
|
|
160
|
-
const errorTips = 'config file ' + chalk.blue(`${filepath}`) + ' does not exist !';
|
|
161
|
-
throw new Error(errorTips)
|
|
162
|
-
}
|
|
163
|
-
const obj = require(filepath);
|
|
164
|
-
if (!obj) return obj;
|
|
165
|
-
|
|
166
|
-
let ret = obj;
|
|
167
|
-
if (is.function(obj) && !is.class(obj)) {
|
|
168
|
-
ret = obj();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return ret || {};
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
exports.sleep = function(ms) {
|
|
175
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
exports.replaceArgsValue = function(argv, key, value) {
|
|
179
|
-
key = key + "=";
|
|
180
|
-
for (let i = 0; i < argv.length; i++) {
|
|
181
|
-
let item = argv[i];
|
|
182
|
-
let pos = item.indexOf(key);
|
|
183
|
-
if (pos !== -1) {
|
|
184
|
-
pos = pos + key.length;
|
|
185
|
-
let tmpStr = item.substring(0, pos);
|
|
186
|
-
argv[i] = tmpStr + value;
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return argv;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
exports.getValueFromArgv = function(argv, key) {
|
|
195
|
-
const argvObj = Pargv(argv);
|
|
196
|
-
if (argvObj.hasOwnProperty(key)) {
|
|
197
|
-
return argvObj[key];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// match search
|
|
201
|
-
key = key + "=";
|
|
202
|
-
let value;
|
|
203
|
-
for (let i = 0; i < argv.length; i++) {
|
|
204
|
-
let item = argv[i];
|
|
205
|
-
let pos = item.indexOf(key);
|
|
206
|
-
if (pos !== -1) {
|
|
207
|
-
pos = pos + key.length;
|
|
208
|
-
value = item.substring(pos);
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return value;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
exports.fileIsExist = function(filepath) {
|
|
217
|
-
if (fs.existsSync(filepath) && fs.statSync(filepath).isFile()) {
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
return false;
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const mkdirp = require('mkdirp');
|
|
3
|
+
const convert = require('koa-convert');
|
|
4
|
+
const is = require('is-type-of');
|
|
5
|
+
const co = require('./co');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const Pargv = require('./pargv');
|
|
9
|
+
|
|
10
|
+
const _basePath = process.cwd();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* fnDebounce
|
|
14
|
+
*
|
|
15
|
+
* @param {Function} fn - 回调函数
|
|
16
|
+
* @param {Time} delayTime - 延迟时间(ms)
|
|
17
|
+
* @param {Boolean} isImediate - 是否需要立即调用
|
|
18
|
+
* @param {type} args - 回调函数传入参数
|
|
19
|
+
*/
|
|
20
|
+
exports.fnDebounce = function() {
|
|
21
|
+
const fnObject = {};
|
|
22
|
+
let timer;
|
|
23
|
+
|
|
24
|
+
return (fn, delayTime, isImediate, args) => {
|
|
25
|
+
const setTimer = () => {
|
|
26
|
+
timer = setTimeout(() => {
|
|
27
|
+
fn(args);
|
|
28
|
+
clearTimeout(timer);
|
|
29
|
+
delete fnObject[fn];
|
|
30
|
+
}, delayTime);
|
|
31
|
+
|
|
32
|
+
fnObject[fn] = { delayTime, timer };
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (!delayTime || isImediate) return fn(args);
|
|
36
|
+
|
|
37
|
+
if (fnObject[fn]) {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
setTimer(fn, delayTime, args);
|
|
40
|
+
} else {
|
|
41
|
+
setTimer(fn, delayTime, args);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 随机10位字符串
|
|
48
|
+
*/
|
|
49
|
+
exports.getRandomString = function() {
|
|
50
|
+
return Math.random().toString(36).substring(2);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 创建文件夹
|
|
55
|
+
*/
|
|
56
|
+
exports.mkdir = function(filepath, opt = {}) {
|
|
57
|
+
mkdirp.sync(filepath, opt);
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 修改文件权限
|
|
63
|
+
*/
|
|
64
|
+
exports.chmodPath = function(path, mode) {
|
|
65
|
+
let files = [];
|
|
66
|
+
if (fs.existsSync(path)) {
|
|
67
|
+
files = fs.readdirSync(path);
|
|
68
|
+
files.forEach((file, index) => {
|
|
69
|
+
const curPath = path + '/' + file;
|
|
70
|
+
if (fs.statSync(curPath).isDirectory()) {
|
|
71
|
+
this.chmodPath(curPath, mode); // 递归删除文件夹
|
|
72
|
+
} else {
|
|
73
|
+
fs.chmodSync(curPath, mode);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
fs.chmodSync(path, mode);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 版本号比较
|
|
82
|
+
*/
|
|
83
|
+
exports.compareVersion = function (v1, v2) {
|
|
84
|
+
v1 = v1.split('.')
|
|
85
|
+
v2 = v2.split('.')
|
|
86
|
+
const len = Math.max(v1.length, v2.length)
|
|
87
|
+
|
|
88
|
+
while (v1.length < len) {
|
|
89
|
+
v1.push('0')
|
|
90
|
+
}
|
|
91
|
+
while (v2.length < len) {
|
|
92
|
+
v2.push('0')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < len; i++) {
|
|
96
|
+
const num1 = parseInt(v1[i])
|
|
97
|
+
const num2 = parseInt(v2[i])
|
|
98
|
+
|
|
99
|
+
if (num1 > num2) {
|
|
100
|
+
return 1
|
|
101
|
+
} else if (num1 < num2) {
|
|
102
|
+
return -1
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return 0
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 执行一个函数
|
|
111
|
+
*/
|
|
112
|
+
exports.callFn = async function (fn, args, ctx) {
|
|
113
|
+
args = args || [];
|
|
114
|
+
if (!is.function(fn)) return;
|
|
115
|
+
if (is.generatorFunction(fn)) fn = co.wrap(fn);
|
|
116
|
+
return ctx ? fn.call(ctx, ...args) : fn(...args);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
exports.middleware = function (fn) {
|
|
120
|
+
return is.generatorFunction(fn) ? convert(fn) : fn;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 序列化对象
|
|
125
|
+
*/
|
|
126
|
+
exports.stringify = function(obj, ignore = []) {
|
|
127
|
+
const result = {};
|
|
128
|
+
Object.keys(obj).forEach(key => {
|
|
129
|
+
if (!ignore.includes(key)) {
|
|
130
|
+
result[key] = obj[key];
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return JSON.stringify(result);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 是否有效值
|
|
138
|
+
*/
|
|
139
|
+
exports.validValue = function(value) {
|
|
140
|
+
return (
|
|
141
|
+
value !== undefined &&
|
|
142
|
+
value !== null &&
|
|
143
|
+
value !== ''
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
exports.checkConfig = function(prop) {
|
|
148
|
+
const filepath = path.join(_basePath, prop);
|
|
149
|
+
if (fs.existsSync(filepath)) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
exports.loadConfig = function(prop) {
|
|
157
|
+
const configFile = prop;
|
|
158
|
+
const filepath = path.join(_basePath, configFile);
|
|
159
|
+
if (!fs.existsSync(filepath)) {
|
|
160
|
+
const errorTips = 'config file ' + chalk.blue(`${filepath}`) + ' does not exist !';
|
|
161
|
+
throw new Error(errorTips)
|
|
162
|
+
}
|
|
163
|
+
const obj = require(filepath);
|
|
164
|
+
if (!obj) return obj;
|
|
165
|
+
|
|
166
|
+
let ret = obj;
|
|
167
|
+
if (is.function(obj) && !is.class(obj)) {
|
|
168
|
+
ret = obj();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return ret || {};
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
exports.sleep = function(ms) {
|
|
175
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
exports.replaceArgsValue = function(argv, key, value) {
|
|
179
|
+
key = key + "=";
|
|
180
|
+
for (let i = 0; i < argv.length; i++) {
|
|
181
|
+
let item = argv[i];
|
|
182
|
+
let pos = item.indexOf(key);
|
|
183
|
+
if (pos !== -1) {
|
|
184
|
+
pos = pos + key.length;
|
|
185
|
+
let tmpStr = item.substring(0, pos);
|
|
186
|
+
argv[i] = tmpStr + value;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return argv;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
exports.getValueFromArgv = function(argv, key) {
|
|
195
|
+
const argvObj = Pargv(argv);
|
|
196
|
+
if (argvObj.hasOwnProperty(key)) {
|
|
197
|
+
return argvObj[key];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// match search
|
|
201
|
+
key = key + "=";
|
|
202
|
+
let value;
|
|
203
|
+
for (let i = 0; i < argv.length; i++) {
|
|
204
|
+
let item = argv[i];
|
|
205
|
+
let pos = item.indexOf(key);
|
|
206
|
+
if (pos !== -1) {
|
|
207
|
+
pos = pos + key.length;
|
|
208
|
+
value = item.substring(pos);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return value;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
exports.fileIsExist = function(filepath) {
|
|
217
|
+
if (fs.existsSync(filepath) && fs.statSync(filepath).isFile()) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
221
|
};
|