@jsenv/node-esm-resolution 1.0.1 → 1.0.2
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/main.js +6 -6
- package/package.json +3 -3
- package/src/custom_conditions.js +8 -8
- package/src/default_lookup_package_scope.js +9 -9
- package/src/default_read_package_json.js +7 -7
- package/src/determine_module_system.js +25 -25
- package/src/errors.js +27 -27
- package/src/filesystem_magic_resolution.js +58 -50
- package/src/node_builtin_specifiers.js +3 -3
- package/src/node_esm_resolution.js +236 -233
- package/src/url_utils.js +33 -30
package/main.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { applyNodeEsmResolution } from "./src/node_esm_resolution.js"
|
|
2
|
-
export { determineModuleSystem } from "./src/determine_module_system.js"
|
|
1
|
+
export { applyNodeEsmResolution } from "./src/node_esm_resolution.js";
|
|
2
|
+
export { determineModuleSystem } from "./src/determine_module_system.js";
|
|
3
3
|
export {
|
|
4
4
|
applyFileSystemMagicResolution,
|
|
5
5
|
getExtensionsToTry,
|
|
6
|
-
} from "./src/filesystem_magic_resolution.js"
|
|
7
|
-
export { defaultLookupPackageScope } from "./src/default_lookup_package_scope.js"
|
|
8
|
-
export { defaultReadPackageJson } from "./src/default_read_package_json.js"
|
|
9
|
-
export { readCustomConditionsFromProcessArgs } from "./src/custom_conditions.js"
|
|
6
|
+
} from "./src/filesystem_magic_resolution.js";
|
|
7
|
+
export { defaultLookupPackageScope } from "./src/default_lookup_package_scope.js";
|
|
8
|
+
export { defaultReadPackageJson } from "./src/default_read_package_json.js";
|
|
9
|
+
export { readCustomConditionsFromProcessArgs } from "./src/custom_conditions.js";
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/node-esm-resolution",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/jsenv/
|
|
8
|
-
"directory": "packages/node-esm-resolution"
|
|
7
|
+
"url": "https://github.com/jsenv/core",
|
|
8
|
+
"directory": "packages/independent/node-esm-resolution"
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
package/src/custom_conditions.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// https://nodejs.org/api/packages.html#resolving-user-conditions
|
|
2
2
|
export const readCustomConditionsFromProcessArgs = () => {
|
|
3
|
-
const packageConditions = []
|
|
3
|
+
const packageConditions = [];
|
|
4
4
|
process.execArgv.forEach((arg) => {
|
|
5
5
|
if (arg.includes("-C=")) {
|
|
6
|
-
const packageCondition = arg.slice(0, "-C=".length)
|
|
7
|
-
packageConditions.push(packageCondition)
|
|
6
|
+
const packageCondition = arg.slice(0, "-C=".length);
|
|
7
|
+
packageConditions.push(packageCondition);
|
|
8
8
|
}
|
|
9
9
|
if (arg.includes("--conditions=")) {
|
|
10
|
-
const packageCondition = arg.slice("--conditions=".length)
|
|
11
|
-
packageConditions.push(packageCondition)
|
|
10
|
+
const packageCondition = arg.slice("--conditions=".length);
|
|
11
|
+
packageConditions.push(packageCondition);
|
|
12
12
|
}
|
|
13
|
-
})
|
|
14
|
-
return packageConditions
|
|
15
|
-
}
|
|
13
|
+
});
|
|
14
|
+
return packageConditions;
|
|
15
|
+
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { existsSync } from "node:fs"
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import { getParentUrl, asDirectoryUrl } from "./url_utils.js"
|
|
3
|
+
import { getParentUrl, asDirectoryUrl } from "./url_utils.js";
|
|
4
4
|
|
|
5
5
|
export const defaultLookupPackageScope = (url) => {
|
|
6
|
-
let scopeUrl = asDirectoryUrl(url)
|
|
6
|
+
let scopeUrl = asDirectoryUrl(url);
|
|
7
7
|
while (scopeUrl !== "file:///") {
|
|
8
8
|
if (scopeUrl.endsWith("node_modules/")) {
|
|
9
|
-
return null
|
|
9
|
+
return null;
|
|
10
10
|
}
|
|
11
|
-
const packageJsonUrlObject = new URL("package.json", scopeUrl)
|
|
11
|
+
const packageJsonUrlObject = new URL("package.json", scopeUrl);
|
|
12
12
|
if (existsSync(packageJsonUrlObject)) {
|
|
13
|
-
return scopeUrl
|
|
13
|
+
return scopeUrl;
|
|
14
14
|
}
|
|
15
|
-
scopeUrl = getParentUrl(scopeUrl)
|
|
15
|
+
scopeUrl = getParentUrl(scopeUrl);
|
|
16
16
|
}
|
|
17
|
-
return null
|
|
18
|
-
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs"
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
2
|
|
|
3
3
|
export const defaultReadPackageJson = (packageUrl) => {
|
|
4
|
-
const packageJsonUrl = new URL("package.json", packageUrl)
|
|
5
|
-
const buffer = readFileSync(packageJsonUrl)
|
|
6
|
-
const string = String(buffer)
|
|
4
|
+
const packageJsonUrl = new URL("package.json", packageUrl);
|
|
5
|
+
const buffer = readFileSync(packageJsonUrl);
|
|
6
|
+
const string = String(buffer);
|
|
7
7
|
try {
|
|
8
|
-
return JSON.parse(string)
|
|
8
|
+
return JSON.parse(string);
|
|
9
9
|
} catch (e) {
|
|
10
|
-
throw new Error(`Invalid package configuration`)
|
|
10
|
+
throw new Error(`Invalid package configuration`);
|
|
11
11
|
}
|
|
12
|
-
}
|
|
12
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defaultLookupPackageScope } from "./default_lookup_package_scope.js"
|
|
2
|
-
import { defaultReadPackageJson } from "./default_read_package_json.js"
|
|
1
|
+
import { defaultLookupPackageScope } from "./default_lookup_package_scope.js";
|
|
2
|
+
import { defaultReadPackageJson } from "./default_read_package_json.js";
|
|
3
3
|
|
|
4
4
|
// https://nodejs.org/dist/latest-v16.x/docs/api/packages.html#packages_determining_module_system)
|
|
5
5
|
export const determineModuleSystem = (
|
|
@@ -8,49 +8,49 @@ export const determineModuleSystem = (
|
|
|
8
8
|
) => {
|
|
9
9
|
const inputTypeArgv = process.execArgv.find((argv) =>
|
|
10
10
|
argv.startsWith("--input-type="),
|
|
11
|
-
)
|
|
11
|
+
);
|
|
12
12
|
if (inputTypeArgv) {
|
|
13
|
-
const value = inputTypeArgv.slice("--input-type=".length)
|
|
13
|
+
const value = inputTypeArgv.slice("--input-type=".length);
|
|
14
14
|
if (value === "module") {
|
|
15
|
-
return "module"
|
|
15
|
+
return "module";
|
|
16
16
|
}
|
|
17
17
|
if (value === "commonjs") {
|
|
18
|
-
return "commonjs"
|
|
18
|
+
return "commonjs";
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
const extension = extensionFromUrl(url)
|
|
21
|
+
const extension = extensionFromUrl(url);
|
|
22
22
|
if (extension === ".mjs") {
|
|
23
|
-
return "module"
|
|
23
|
+
return "module";
|
|
24
24
|
}
|
|
25
25
|
if (extension === ".cjs") {
|
|
26
|
-
return "commonjs"
|
|
26
|
+
return "commonjs";
|
|
27
27
|
}
|
|
28
28
|
if (extension === ".json") {
|
|
29
|
-
return "url"
|
|
29
|
+
return "url";
|
|
30
30
|
}
|
|
31
31
|
if (ambiguousExtensions.includes(extension)) {
|
|
32
|
-
const packageDirectoryUrl = defaultLookupPackageScope(url)
|
|
32
|
+
const packageDirectoryUrl = defaultLookupPackageScope(url);
|
|
33
33
|
if (!packageDirectoryUrl) {
|
|
34
|
-
return "commonjs"
|
|
34
|
+
return "commonjs";
|
|
35
35
|
}
|
|
36
|
-
const packageJson = defaultReadPackageJson(packageDirectoryUrl)
|
|
36
|
+
const packageJson = defaultReadPackageJson(packageDirectoryUrl);
|
|
37
37
|
if (packageJson.type === "module") {
|
|
38
|
-
return "module"
|
|
38
|
+
return "module";
|
|
39
39
|
}
|
|
40
|
-
return "commonjs"
|
|
40
|
+
return "commonjs";
|
|
41
41
|
}
|
|
42
|
-
return "url"
|
|
42
|
+
return "url";
|
|
43
43
|
// throw new Error(`unsupported file extension (${extension})`)
|
|
44
|
-
}
|
|
44
|
+
};
|
|
45
45
|
|
|
46
46
|
const extensionFromUrl = (url) => {
|
|
47
|
-
const { pathname } = new URL(url)
|
|
48
|
-
const slashLastIndex = pathname.lastIndexOf("/")
|
|
47
|
+
const { pathname } = new URL(url);
|
|
48
|
+
const slashLastIndex = pathname.lastIndexOf("/");
|
|
49
49
|
const filename =
|
|
50
|
-
slashLastIndex === -1 ? pathname : pathname.slice(slashLastIndex + 1)
|
|
51
|
-
const dotLastIndex = filename.lastIndexOf(".")
|
|
52
|
-
if (dotLastIndex === -1) return ""
|
|
50
|
+
slashLastIndex === -1 ? pathname : pathname.slice(slashLastIndex + 1);
|
|
51
|
+
const dotLastIndex = filename.lastIndexOf(".");
|
|
52
|
+
if (dotLastIndex === -1) return "";
|
|
53
53
|
// if (dotLastIndex === pathname.length - 1) return ""
|
|
54
|
-
const extension = filename.slice(dotLastIndex)
|
|
55
|
-
return extension
|
|
56
|
-
}
|
|
54
|
+
const extension = filename.slice(dotLastIndex);
|
|
55
|
+
return extension;
|
|
56
|
+
};
|
package/src/errors.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// https://github.com/nodejs/node/blob/0367b5c35ea0f98b323175a4aaa8e651af7a91e7/tools/node_modules/eslint/node_modules/%40babel/core/lib/vendor/import-meta-resolve.js#L2473
|
|
2
|
-
import { fileURLToPath } from "node:url"
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
3
|
|
|
4
4
|
export const createInvalidModuleSpecifierError = (
|
|
5
5
|
reason,
|
|
@@ -10,59 +10,59 @@ export const createInvalidModuleSpecifierError = (
|
|
|
10
10
|
`Invalid module "${specifier}" ${reason} imported from ${fileURLToPath(
|
|
11
11
|
parentUrl,
|
|
12
12
|
)}`,
|
|
13
|
-
)
|
|
14
|
-
error.code = "INVALID_MODULE_SPECIFIER"
|
|
15
|
-
return error
|
|
16
|
-
}
|
|
13
|
+
);
|
|
14
|
+
error.code = "INVALID_MODULE_SPECIFIER";
|
|
15
|
+
return error;
|
|
16
|
+
};
|
|
17
17
|
|
|
18
18
|
export const createInvalidPackageTargetError = (
|
|
19
19
|
reason,
|
|
20
20
|
target,
|
|
21
21
|
{ parentUrl, packageDirectoryUrl, key, isImport },
|
|
22
22
|
) => {
|
|
23
|
-
let message
|
|
23
|
+
let message;
|
|
24
24
|
if (key === ".") {
|
|
25
25
|
message = `Invalid "exports" main target defined in ${fileURLToPath(
|
|
26
26
|
packageDirectoryUrl,
|
|
27
|
-
)}package.json imported from ${fileURLToPath(parentUrl)}; ${reason}
|
|
27
|
+
)}package.json imported from ${fileURLToPath(parentUrl)}; ${reason}`;
|
|
28
28
|
} else {
|
|
29
29
|
message = `Invalid "${
|
|
30
30
|
isImport ? "imports" : "exports"
|
|
31
31
|
}" target ${JSON.stringify(target)} defined for "${key}" in ${fileURLToPath(
|
|
32
32
|
packageDirectoryUrl,
|
|
33
|
-
)}package.json imported from ${fileURLToPath(parentUrl)}; ${reason}
|
|
33
|
+
)}package.json imported from ${fileURLToPath(parentUrl)}; ${reason}`;
|
|
34
34
|
}
|
|
35
|
-
const error = new Error(message)
|
|
36
|
-
error.code = "INVALID_PACKAGE_TARGET"
|
|
37
|
-
return error
|
|
38
|
-
}
|
|
35
|
+
const error = new Error(message);
|
|
36
|
+
error.code = "INVALID_PACKAGE_TARGET";
|
|
37
|
+
return error;
|
|
38
|
+
};
|
|
39
39
|
|
|
40
40
|
export const createPackagePathNotExportedError = (
|
|
41
41
|
subpath,
|
|
42
42
|
{ parentUrl, packageDirectoryUrl },
|
|
43
43
|
) => {
|
|
44
|
-
let message
|
|
44
|
+
let message;
|
|
45
45
|
if (subpath === ".") {
|
|
46
46
|
message = `No "exports" main defined in ${fileURLToPath(
|
|
47
47
|
packageDirectoryUrl,
|
|
48
|
-
)}package.json imported from ${fileURLToPath(parentUrl)}
|
|
48
|
+
)}package.json imported from ${fileURLToPath(parentUrl)}`;
|
|
49
49
|
} else {
|
|
50
50
|
message = `Package subpath "${subpath}" is not defined by "exports" in ${fileURLToPath(
|
|
51
51
|
packageDirectoryUrl,
|
|
52
|
-
)}package.json imported from ${fileURLToPath(parentUrl)}
|
|
52
|
+
)}package.json imported from ${fileURLToPath(parentUrl)}`;
|
|
53
53
|
}
|
|
54
|
-
const error = new Error(message)
|
|
55
|
-
error.code = "PACKAGE_PATH_NOT_EXPORTED"
|
|
56
|
-
return error
|
|
57
|
-
}
|
|
54
|
+
const error = new Error(message);
|
|
55
|
+
error.code = "PACKAGE_PATH_NOT_EXPORTED";
|
|
56
|
+
return error;
|
|
57
|
+
};
|
|
58
58
|
|
|
59
59
|
export const createModuleNotFoundError = (specifier, { parentUrl }) => {
|
|
60
60
|
const error = new Error(
|
|
61
61
|
`Cannot find "${specifier}" imported from ${fileURLToPath(parentUrl)}`,
|
|
62
|
-
)
|
|
63
|
-
error.code = "MODULE_NOT_FOUND"
|
|
64
|
-
return error
|
|
65
|
-
}
|
|
62
|
+
);
|
|
63
|
+
error.code = "MODULE_NOT_FOUND";
|
|
64
|
+
return error;
|
|
65
|
+
};
|
|
66
66
|
|
|
67
67
|
export const createPackageImportNotDefinedError = (
|
|
68
68
|
specifier,
|
|
@@ -72,7 +72,7 @@ export const createPackageImportNotDefinedError = (
|
|
|
72
72
|
`Package import specifier "${specifier}" is not defined in ${fileURLToPath(
|
|
73
73
|
packageDirectoryUrl,
|
|
74
74
|
)}package.json imported from ${fileURLToPath(parentUrl)}`,
|
|
75
|
-
)
|
|
76
|
-
error.code = "PACKAGE_IMPORT_NOT_DEFINED"
|
|
77
|
-
return error
|
|
78
|
-
}
|
|
75
|
+
);
|
|
76
|
+
error.code = "PACKAGE_IMPORT_NOT_DEFINED";
|
|
77
|
+
return error;
|
|
78
|
+
};
|
|
@@ -1,87 +1,95 @@
|
|
|
1
|
-
import { statSync } from "node:fs"
|
|
1
|
+
import { statSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import { urlToFilename, urlToExtension } from "./url_utils.js"
|
|
3
|
+
import { urlToFilename, urlToExtension } from "./url_utils.js";
|
|
4
4
|
|
|
5
5
|
export const applyFileSystemMagicResolution = (
|
|
6
6
|
fileUrl,
|
|
7
7
|
{ fileStat, magicDirectoryIndex, magicExtensions },
|
|
8
8
|
) => {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const result = {
|
|
10
|
+
stat: null,
|
|
11
|
+
url: fileUrl,
|
|
12
|
+
magicExtension: "",
|
|
13
|
+
magicDirectoryIndex: false,
|
|
14
|
+
lastENOENTError: null,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (fileStat === undefined) {
|
|
11
18
|
try {
|
|
12
|
-
|
|
19
|
+
fileStat = statSync(new URL(fileUrl));
|
|
13
20
|
} catch (e) {
|
|
14
21
|
if (e.code === "ENOENT") {
|
|
15
|
-
lastENOENTError = e
|
|
16
|
-
|
|
22
|
+
result.lastENOENTError = e;
|
|
23
|
+
fileStat = null;
|
|
24
|
+
} else {
|
|
25
|
+
throw e;
|
|
17
26
|
}
|
|
18
|
-
throw e
|
|
19
27
|
}
|
|
20
28
|
}
|
|
21
|
-
fileStat = fileStat === undefined ? fileStatOrNull(fileUrl) : fileStat
|
|
22
29
|
|
|
23
30
|
if (fileStat && fileStat.isFile()) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
31
|
+
result.stat = fileStat;
|
|
32
|
+
result.url = fileUrl;
|
|
33
|
+
return result;
|
|
28
34
|
}
|
|
29
35
|
if (fileStat && fileStat.isDirectory()) {
|
|
30
36
|
if (magicDirectoryIndex) {
|
|
31
|
-
const indexFileSuffix = fileUrl.endsWith("/") ? "index" : "/index"
|
|
32
|
-
const indexFileUrl = `${fileUrl}${indexFileSuffix}
|
|
33
|
-
const
|
|
37
|
+
const indexFileSuffix = fileUrl.endsWith("/") ? "index" : "/index";
|
|
38
|
+
const indexFileUrl = `${fileUrl}${indexFileSuffix}`;
|
|
39
|
+
const subResult = applyFileSystemMagicResolution(indexFileUrl, {
|
|
34
40
|
magicDirectoryIndex: false,
|
|
35
41
|
magicExtensions,
|
|
36
|
-
})
|
|
42
|
+
});
|
|
37
43
|
return {
|
|
38
44
|
...result,
|
|
45
|
+
...subResult,
|
|
39
46
|
magicDirectoryIndex: true,
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
found: true,
|
|
44
|
-
url: fileUrl,
|
|
45
|
-
isDirectory: true,
|
|
47
|
+
};
|
|
46
48
|
}
|
|
49
|
+
result.stat = fileStat;
|
|
50
|
+
result.url = fileUrl;
|
|
51
|
+
return result;
|
|
47
52
|
}
|
|
53
|
+
|
|
48
54
|
if (magicExtensions && magicExtensions.length) {
|
|
49
|
-
const parentUrl = new URL("./", fileUrl).href
|
|
50
|
-
const urlFilename = urlToFilename(fileUrl)
|
|
51
|
-
const
|
|
52
|
-
const urlCandidate = `${parentUrl}${urlFilename}${extensionToTry}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
const parentUrl = new URL("./", fileUrl).href;
|
|
56
|
+
const urlFilename = urlToFilename(fileUrl);
|
|
57
|
+
for (const extensionToTry of magicExtensions) {
|
|
58
|
+
const urlCandidate = `${parentUrl}${urlFilename}${extensionToTry}`;
|
|
59
|
+
let stat;
|
|
60
|
+
try {
|
|
61
|
+
stat = statSync(new URL(urlCandidate));
|
|
62
|
+
} catch (e) {
|
|
63
|
+
if (e.code === "ENOENT") {
|
|
64
|
+
stat = null;
|
|
65
|
+
} else {
|
|
66
|
+
throw e;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (stat) {
|
|
70
|
+
result.stat = stat;
|
|
71
|
+
result.url = `${fileUrl}${extensionToTry}`;
|
|
72
|
+
result.magicExtension = extensionToTry;
|
|
73
|
+
return result;
|
|
62
74
|
}
|
|
63
75
|
}
|
|
64
76
|
}
|
|
65
77
|
// magic extension not found
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
url: fileUrl,
|
|
69
|
-
lastENOENTError,
|
|
70
|
-
}
|
|
71
|
-
}
|
|
78
|
+
return result;
|
|
79
|
+
};
|
|
72
80
|
|
|
73
81
|
export const getExtensionsToTry = (magicExtensions, importer) => {
|
|
74
82
|
if (!magicExtensions) {
|
|
75
|
-
return []
|
|
83
|
+
return [];
|
|
76
84
|
}
|
|
77
|
-
const extensionsSet = new Set()
|
|
85
|
+
const extensionsSet = new Set();
|
|
78
86
|
magicExtensions.forEach((magicExtension) => {
|
|
79
87
|
if (magicExtension === "inherit") {
|
|
80
|
-
const importerExtension = urlToExtension(importer)
|
|
81
|
-
extensionsSet.add(importerExtension)
|
|
88
|
+
const importerExtension = urlToExtension(importer);
|
|
89
|
+
extensionsSet.add(importerExtension);
|
|
82
90
|
} else {
|
|
83
|
-
extensionsSet.add(magicExtension)
|
|
91
|
+
extensionsSet.add(magicExtension);
|
|
84
92
|
}
|
|
85
|
-
})
|
|
86
|
-
return Array.from(extensionsSet.values())
|
|
87
|
-
}
|
|
93
|
+
});
|
|
94
|
+
return Array.from(extensionsSet.values());
|
|
95
|
+
};
|
|
@@ -2,8 +2,8 @@ export const isSpecifierForNodeBuiltin = (specifier) => {
|
|
|
2
2
|
return (
|
|
3
3
|
specifier.startsWith("node:") ||
|
|
4
4
|
NODE_BUILTIN_MODULE_SPECIFIERS.includes(specifier)
|
|
5
|
-
)
|
|
6
|
-
}
|
|
5
|
+
);
|
|
6
|
+
};
|
|
7
7
|
|
|
8
8
|
const NODE_BUILTIN_MODULE_SPECIFIERS = [
|
|
9
9
|
"assert",
|
|
@@ -81,4 +81,4 @@ const NODE_BUILTIN_MODULE_SPECIFIERS = [
|
|
|
81
81
|
"zlib",
|
|
82
82
|
// global is special
|
|
83
83
|
"global",
|
|
84
|
-
]
|
|
84
|
+
];
|