metro-file-map 0.73.7 → 0.74.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/package.json +1 -1
- package/src/HasteFS.js +84 -11
- package/src/HasteFS.js.flow +92 -9
- package/src/Watcher.js +1 -1
- package/src/Watcher.js.flow +3 -3
- package/src/cache/DiskCacheManager.js.flow +3 -3
- package/src/constants.js +1 -0
- package/src/constants.js.flow +1 -0
- package/src/crawlers/__fixtures__/directory/bar.js +11 -0
- package/src/crawlers/__fixtures__/directory/bar.js.flow +10 -0
- package/src/crawlers/__fixtures__/directory/other.file +0 -0
- package/src/crawlers/__fixtures__/foo.js +11 -0
- package/src/crawlers/__fixtures__/foo.js.flow +10 -0
- package/src/crawlers/__fixtures__/ignored/hidden.js +11 -0
- package/src/crawlers/__fixtures__/ignored/hidden.js.flow +10 -0
- package/src/crawlers/__fixtures__/link-to-directory/bar.js +11 -0
- package/src/crawlers/__fixtures__/link-to-directory/bar.js.flow +10 -0
- package/src/crawlers/__fixtures__/link-to-directory/other.file +0 -0
- package/src/crawlers/__fixtures__/link-to-foo.js +11 -0
- package/src/crawlers/__fixtures__/link-to-foo.js.flow +10 -0
- package/src/crawlers/node/hasNativeFindSupport.js +48 -0
- package/src/crawlers/node/hasNativeFindSupport.js.flow +41 -0
- package/src/crawlers/{node.js → node/index.js} +66 -95
- package/src/crawlers/node/index.js.flow +223 -0
- package/src/crawlers/watchman/index.js +35 -14
- package/src/crawlers/watchman/index.js.flow +38 -17
- package/src/crawlers/watchman/planQuery.js +15 -1
- package/src/crawlers/watchman/planQuery.js.flow +15 -1
- package/src/flow-types.js.flow +36 -15
- package/src/index.js +253 -218
- package/src/index.js.flow +220 -207
- package/src/lib/{deepCloneInternalData.js → deepCloneRawModuleMap.js} +6 -9
- package/src/lib/{deepCloneInternalData.js.flow → deepCloneRawModuleMap.js.flow} +9 -12
- package/src/watchers/FSEventsWatcher.js +34 -26
- package/src/watchers/FSEventsWatcher.js.flow +38 -33
- package/src/watchers/NodeWatcher.js +62 -36
- package/src/watchers/NodeWatcher.js.flow +63 -36
- package/src/watchers/common.js +2 -0
- package/src/watchers/common.js.flow +2 -0
- package/src/worker.js +48 -43
- package/src/worker.js.flow +57 -55
- package/src/crawlers/node.js.flow +0 -250
package/package.json
CHANGED
package/src/HasteFS.js
CHANGED
|
@@ -65,18 +65,78 @@ class HasteFS {
|
|
|
65
65
|
#rootDir;
|
|
66
66
|
#files;
|
|
67
67
|
constructor({ rootDir, files }) {
|
|
68
|
-
// $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
|
|
69
68
|
this.#rootDir = rootDir;
|
|
70
|
-
// $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
|
|
71
69
|
this.#files = files;
|
|
72
70
|
}
|
|
71
|
+
_normalizePath(relativeOrAbsolutePath) {
|
|
72
|
+
return path.isAbsolute(relativeOrAbsolutePath)
|
|
73
|
+
? fastPath.relative(this.#rootDir, relativeOrAbsolutePath)
|
|
74
|
+
: path.normalize(relativeOrAbsolutePath);
|
|
75
|
+
}
|
|
76
|
+
remove(filePath) {
|
|
77
|
+
this.#files.delete(this._normalizePath(filePath));
|
|
78
|
+
}
|
|
79
|
+
bulkAddOrModify(changedFiles) {
|
|
80
|
+
for (const [relativePath, metadata] of changedFiles) {
|
|
81
|
+
this.#files.set(relativePath, metadata);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
addOrModify(filePath, metadata) {
|
|
85
|
+
this.#files.set(this._normalizePath(filePath), metadata);
|
|
86
|
+
}
|
|
87
|
+
setVisitMetadata(filePath, visitResult) {
|
|
88
|
+
const metadata = this._getFileData(filePath);
|
|
89
|
+
if (!metadata) {
|
|
90
|
+
throw new Error("Visited file not found in file map: " + filePath);
|
|
91
|
+
}
|
|
92
|
+
metadata[_constants.default.VISITED] = 1;
|
|
93
|
+
if (visitResult.hasteId != null) {
|
|
94
|
+
metadata[_constants.default.ID] = visitResult.hasteId;
|
|
95
|
+
}
|
|
96
|
+
if ("sha1" in visitResult) {
|
|
97
|
+
metadata[_constants.default.SHA1] = visitResult.sha1;
|
|
98
|
+
}
|
|
99
|
+
if (visitResult.dependencies != null) {
|
|
100
|
+
metadata[_constants.default.DEPENDENCIES] = visitResult.dependencies;
|
|
101
|
+
}
|
|
102
|
+
if (visitResult.symlinkTarget != null) {
|
|
103
|
+
metadata[_constants.default.SYMLINK] = visitResult.symlinkTarget;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
getSerializableSnapshot() {
|
|
107
|
+
return new Map(Array.from(this.#files.entries(), ([k, v]) => [k, [...v]]));
|
|
108
|
+
}
|
|
73
109
|
getModuleName(file) {
|
|
110
|
+
var _ref;
|
|
74
111
|
const fileMetadata = this._getFileData(file);
|
|
75
|
-
return (fileMetadata && fileMetadata[_constants.default.ID])
|
|
112
|
+
return (_ref = fileMetadata && fileMetadata[_constants.default.ID]) !==
|
|
113
|
+
null && _ref !== void 0
|
|
114
|
+
? _ref
|
|
115
|
+
: null;
|
|
76
116
|
}
|
|
77
117
|
getSize(file) {
|
|
118
|
+
var _ref2;
|
|
78
119
|
const fileMetadata = this._getFileData(file);
|
|
79
|
-
return (fileMetadata && fileMetadata[_constants.default.SIZE])
|
|
120
|
+
return (_ref2 = fileMetadata && fileMetadata[_constants.default.SIZE]) !==
|
|
121
|
+
null && _ref2 !== void 0
|
|
122
|
+
? _ref2
|
|
123
|
+
: null;
|
|
124
|
+
}
|
|
125
|
+
getSymlinkTarget(file) {
|
|
126
|
+
const fileMetadata = this._getFileData(file);
|
|
127
|
+
if (fileMetadata == null) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return typeof fileMetadata[_constants.default.SYMLINK] === "string"
|
|
131
|
+
? fileMetadata[_constants.default.SYMLINK]
|
|
132
|
+
: null;
|
|
133
|
+
}
|
|
134
|
+
getType(file) {
|
|
135
|
+
const fileMetadata = this._getFileData(file);
|
|
136
|
+
if (fileMetadata == null) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return fileMetadata[_constants.default.SYMLINK] === 0 ? "f" : "l";
|
|
80
140
|
}
|
|
81
141
|
getDependencies(file) {
|
|
82
142
|
const fileMetadata = this._getFileData(file);
|
|
@@ -91,11 +151,19 @@ class HasteFS {
|
|
|
91
151
|
}
|
|
92
152
|
}
|
|
93
153
|
getSha1(file) {
|
|
94
|
-
var
|
|
154
|
+
var _ref3;
|
|
95
155
|
const fileMetadata = this._getFileData(file);
|
|
96
|
-
return (
|
|
97
|
-
null &&
|
|
98
|
-
?
|
|
156
|
+
return (_ref3 = fileMetadata && fileMetadata[_constants.default.SHA1]) !==
|
|
157
|
+
null && _ref3 !== void 0
|
|
158
|
+
? _ref3
|
|
159
|
+
: null;
|
|
160
|
+
}
|
|
161
|
+
getModifiedTime(file) {
|
|
162
|
+
var _ref4;
|
|
163
|
+
const fileMetadata = this._getFileData(file);
|
|
164
|
+
return (_ref4 = fileMetadata && fileMetadata[_constants.default.MTIME]) !==
|
|
165
|
+
null && _ref4 !== void 0
|
|
166
|
+
? _ref4
|
|
99
167
|
: null;
|
|
100
168
|
}
|
|
101
169
|
exists(file) {
|
|
@@ -168,9 +236,14 @@ class HasteFS {
|
|
|
168
236
|
}
|
|
169
237
|
return files;
|
|
170
238
|
}
|
|
171
|
-
_getFileData(
|
|
172
|
-
|
|
173
|
-
|
|
239
|
+
_getFileData(filePath) {
|
|
240
|
+
// Shortcut to avoid any file path parsing if the given path is already
|
|
241
|
+
// normalised.
|
|
242
|
+
const optimisticMetadata = this.#files.get(filePath);
|
|
243
|
+
if (optimisticMetadata) {
|
|
244
|
+
return optimisticMetadata;
|
|
245
|
+
}
|
|
246
|
+
return this.#files.get(this._normalizePath(filePath));
|
|
174
247
|
}
|
|
175
248
|
}
|
|
176
249
|
exports.default = HasteFS;
|
package/src/HasteFS.js.flow
CHANGED
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
import type {
|
|
12
12
|
FileData,
|
|
13
13
|
FileMetaData,
|
|
14
|
-
FileSystem,
|
|
15
14
|
Glob,
|
|
15
|
+
MutableFileSystem,
|
|
16
16
|
Path,
|
|
17
|
+
VisitMetadata,
|
|
17
18
|
} from './flow-types';
|
|
18
19
|
|
|
19
20
|
import H from './constants';
|
|
@@ -21,25 +22,97 @@ import * as fastPath from './lib/fast_path';
|
|
|
21
22
|
import * as path from 'path';
|
|
22
23
|
import {globsToMatcher, replacePathSepForGlob} from 'jest-util';
|
|
23
24
|
|
|
24
|
-
export default class HasteFS implements
|
|
25
|
+
export default class HasteFS implements MutableFileSystem {
|
|
25
26
|
+#rootDir: Path;
|
|
26
27
|
+#files: FileData;
|
|
27
28
|
|
|
28
29
|
constructor({rootDir, files}: {rootDir: Path, files: FileData}) {
|
|
29
|
-
// $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
|
|
30
30
|
this.#rootDir = rootDir;
|
|
31
|
-
// $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
|
|
32
31
|
this.#files = files;
|
|
33
32
|
}
|
|
34
33
|
|
|
34
|
+
_normalizePath(relativeOrAbsolutePath: Path): string {
|
|
35
|
+
return path.isAbsolute(relativeOrAbsolutePath)
|
|
36
|
+
? fastPath.relative(this.#rootDir, relativeOrAbsolutePath)
|
|
37
|
+
: path.normalize(relativeOrAbsolutePath);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
remove(filePath: Path) {
|
|
41
|
+
this.#files.delete(this._normalizePath(filePath));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
bulkAddOrModify(changedFiles: FileData) {
|
|
45
|
+
for (const [relativePath, metadata] of changedFiles) {
|
|
46
|
+
this.#files.set(relativePath, metadata);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
addOrModify(filePath: Path, metadata: FileMetaData) {
|
|
51
|
+
this.#files.set(this._normalizePath(filePath), metadata);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setVisitMetadata(
|
|
55
|
+
filePath: Path,
|
|
56
|
+
visitResult: $ReadOnly<VisitMetadata>,
|
|
57
|
+
): void {
|
|
58
|
+
const metadata = this._getFileData(filePath);
|
|
59
|
+
if (!metadata) {
|
|
60
|
+
throw new Error('Visited file not found in file map: ' + filePath);
|
|
61
|
+
}
|
|
62
|
+
metadata[H.VISITED] = 1;
|
|
63
|
+
|
|
64
|
+
if (visitResult.hasteId != null) {
|
|
65
|
+
metadata[H.ID] = visitResult.hasteId;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ('sha1' in visitResult) {
|
|
69
|
+
metadata[H.SHA1] = visitResult.sha1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (visitResult.dependencies != null) {
|
|
73
|
+
metadata[H.DEPENDENCIES] = visitResult.dependencies;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (visitResult.symlinkTarget != null) {
|
|
77
|
+
metadata[H.SYMLINK] = visitResult.symlinkTarget;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getSerializableSnapshot(): FileData {
|
|
82
|
+
return new Map(
|
|
83
|
+
Array.from(this.#files.entries(), ([k, v]: [Path, FileMetaData]) => [
|
|
84
|
+
k,
|
|
85
|
+
[...v],
|
|
86
|
+
]),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
35
90
|
getModuleName(file: Path): ?string {
|
|
36
91
|
const fileMetadata = this._getFileData(file);
|
|
37
|
-
return (fileMetadata && fileMetadata[H.ID])
|
|
92
|
+
return (fileMetadata && fileMetadata[H.ID]) ?? null;
|
|
38
93
|
}
|
|
39
94
|
|
|
40
95
|
getSize(file: Path): ?number {
|
|
41
96
|
const fileMetadata = this._getFileData(file);
|
|
42
|
-
return (fileMetadata && fileMetadata[H.SIZE])
|
|
97
|
+
return (fileMetadata && fileMetadata[H.SIZE]) ?? null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getSymlinkTarget(file: Path): ?string {
|
|
101
|
+
const fileMetadata = this._getFileData(file);
|
|
102
|
+
if (fileMetadata == null) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return typeof fileMetadata[H.SYMLINK] === 'string'
|
|
106
|
+
? fileMetadata[H.SYMLINK]
|
|
107
|
+
: null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
getType(file: Path): ?('f' | 'l') {
|
|
111
|
+
const fileMetadata = this._getFileData(file);
|
|
112
|
+
if (fileMetadata == null) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return fileMetadata[H.SYMLINK] === 0 ? 'f' : 'l';
|
|
43
116
|
}
|
|
44
117
|
|
|
45
118
|
getDependencies(file: Path): ?Array<string> {
|
|
@@ -59,6 +132,11 @@ export default class HasteFS implements FileSystem {
|
|
|
59
132
|
return (fileMetadata && fileMetadata[H.SHA1]) ?? null;
|
|
60
133
|
}
|
|
61
134
|
|
|
135
|
+
getModifiedTime(file: Path): ?number {
|
|
136
|
+
const fileMetadata = this._getFileData(file);
|
|
137
|
+
return (fileMetadata && fileMetadata[H.MTIME]) ?? null;
|
|
138
|
+
}
|
|
139
|
+
|
|
62
140
|
exists(file: Path): boolean {
|
|
63
141
|
return this._getFileData(file) != null;
|
|
64
142
|
}
|
|
@@ -148,8 +226,13 @@ export default class HasteFS implements FileSystem {
|
|
|
148
226
|
return files;
|
|
149
227
|
}
|
|
150
228
|
|
|
151
|
-
_getFileData(
|
|
152
|
-
|
|
153
|
-
|
|
229
|
+
_getFileData(filePath: Path): void | FileMetaData {
|
|
230
|
+
// Shortcut to avoid any file path parsing if the given path is already
|
|
231
|
+
// normalised.
|
|
232
|
+
const optimisticMetadata = this.#files.get(filePath);
|
|
233
|
+
if (optimisticMetadata) {
|
|
234
|
+
return optimisticMetadata;
|
|
235
|
+
}
|
|
236
|
+
return this.#files.get(this._normalizePath(filePath));
|
|
154
237
|
}
|
|
155
238
|
}
|
package/src/Watcher.js
CHANGED
|
@@ -101,7 +101,7 @@ class Watcher extends _events.default {
|
|
|
101
101
|
const crawlerOptions = {
|
|
102
102
|
abortSignal: options.abortSignal,
|
|
103
103
|
computeSha1: options.computeSha1,
|
|
104
|
-
|
|
104
|
+
includeSymlinks: options.enableSymlinks,
|
|
105
105
|
extensions: options.extensions,
|
|
106
106
|
forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
|
|
107
107
|
ignore,
|
package/src/Watcher.js.flow
CHANGED
|
@@ -100,7 +100,7 @@ export class Watcher extends EventEmitter {
|
|
|
100
100
|
const crawlerOptions: CrawlerOptions = {
|
|
101
101
|
abortSignal: options.abortSignal,
|
|
102
102
|
computeSha1: options.computeSha1,
|
|
103
|
-
|
|
103
|
+
includeSymlinks: options.enableSymlinks,
|
|
104
104
|
extensions: options.extensions,
|
|
105
105
|
forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
|
|
106
106
|
ignore,
|
|
@@ -162,7 +162,7 @@ export class Watcher extends EventEmitter {
|
|
|
162
162
|
type: string,
|
|
163
163
|
filePath: string,
|
|
164
164
|
root: string,
|
|
165
|
-
metadata:
|
|
165
|
+
metadata: ChangeEventMetadata,
|
|
166
166
|
) => void,
|
|
167
167
|
) {
|
|
168
168
|
const {extensions, ignorePattern, useWatchman} = this._options;
|
|
@@ -214,7 +214,7 @@ export class Watcher extends EventEmitter {
|
|
|
214
214
|
type: string,
|
|
215
215
|
filePath: string,
|
|
216
216
|
root: string,
|
|
217
|
-
metadata:
|
|
217
|
+
metadata: ChangeEventMetadata,
|
|
218
218
|
) => {
|
|
219
219
|
const basename = path.basename(filePath);
|
|
220
220
|
if (basename.startsWith(this._options.healthCheckFilePrefix)) {
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
import type {
|
|
13
13
|
BuildParameters,
|
|
14
|
+
CacheData,
|
|
14
15
|
CacheManager,
|
|
15
16
|
FileData,
|
|
16
|
-
InternalData,
|
|
17
17
|
} from '../flow-types';
|
|
18
18
|
|
|
19
19
|
import rootRelativeCacheKeys from '../lib/rootRelativeCacheKeys';
|
|
@@ -66,7 +66,7 @@ export class DiskCacheManager implements CacheManager {
|
|
|
66
66
|
return this._cachePath;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
async read(): Promise<?
|
|
69
|
+
async read(): Promise<?CacheData> {
|
|
70
70
|
try {
|
|
71
71
|
return deserialize(readFileSync(this._cachePath));
|
|
72
72
|
} catch (e) {
|
|
@@ -80,7 +80,7 @@ export class DiskCacheManager implements CacheManager {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
async write(
|
|
83
|
-
dataSnapshot:
|
|
83
|
+
dataSnapshot: CacheData,
|
|
84
84
|
{changed, removed}: $ReadOnly<{changed: FileData, removed: FileData}>,
|
|
85
85
|
): Promise<void> {
|
|
86
86
|
if (changed.size > 0 || removed.size > 0) {
|
package/src/constants.js
CHANGED
package/src/constants.js.flow
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true,
|
|
5
|
+
});
|
|
6
|
+
exports.default = hasNativeFindSupport;
|
|
7
|
+
var _child_process = require("child_process");
|
|
8
|
+
/**
|
|
9
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
10
|
+
*
|
|
11
|
+
* This source code is licensed under the MIT license found in the
|
|
12
|
+
* LICENSE file in the root directory of this source tree.
|
|
13
|
+
*
|
|
14
|
+
*
|
|
15
|
+
* @format
|
|
16
|
+
* @oncall react_native
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
async function hasNativeFindSupport() {
|
|
20
|
+
try {
|
|
21
|
+
return await new Promise((resolve) => {
|
|
22
|
+
// Check the find binary supports the non-POSIX -iname parameter wrapped in parens.
|
|
23
|
+
const args = [
|
|
24
|
+
".",
|
|
25
|
+
"-type",
|
|
26
|
+
"f",
|
|
27
|
+
"(",
|
|
28
|
+
"-iname",
|
|
29
|
+
"*.ts",
|
|
30
|
+
"-o",
|
|
31
|
+
"-iname",
|
|
32
|
+
"*.js",
|
|
33
|
+
")",
|
|
34
|
+
];
|
|
35
|
+
const child = (0, _child_process.spawn)("find", args, {
|
|
36
|
+
cwd: __dirname,
|
|
37
|
+
});
|
|
38
|
+
child.on("error", () => {
|
|
39
|
+
resolve(false);
|
|
40
|
+
});
|
|
41
|
+
child.on("exit", (code) => {
|
|
42
|
+
resolve(code === 0);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall react_native
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {spawn} from 'child_process';
|
|
13
|
+
|
|
14
|
+
export default async function hasNativeFindSupport(): Promise<boolean> {
|
|
15
|
+
try {
|
|
16
|
+
return await new Promise(resolve => {
|
|
17
|
+
// Check the find binary supports the non-POSIX -iname parameter wrapped in parens.
|
|
18
|
+
const args = [
|
|
19
|
+
'.',
|
|
20
|
+
'-type',
|
|
21
|
+
'f',
|
|
22
|
+
'(',
|
|
23
|
+
'-iname',
|
|
24
|
+
'*.ts',
|
|
25
|
+
'-o',
|
|
26
|
+
'-iname',
|
|
27
|
+
'*.js',
|
|
28
|
+
')',
|
|
29
|
+
];
|
|
30
|
+
const child = spawn('find', args, {cwd: __dirname});
|
|
31
|
+
child.on('error', () => {
|
|
32
|
+
resolve(false);
|
|
33
|
+
});
|
|
34
|
+
child.on('exit', code => {
|
|
35
|
+
resolve(code === 0);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|