isomorphic-git 1.37.4 → 1.37.6
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/index.cjs +111 -79
- package/index.js +104 -79
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +20 -5
- package/managers/index.js +13 -5
- package/managers/index.umd.min.js +1 -1
- package/managers/index.umd.min.js.map +1 -1
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -8,6 +8,7 @@ var AsyncLock = _interopDefault(require('async-lock'));
|
|
|
8
8
|
var Hash = _interopDefault(require('sha.js/sha1.js'));
|
|
9
9
|
var crc32 = _interopDefault(require('crc-32'));
|
|
10
10
|
var pako = _interopDefault(require('pako'));
|
|
11
|
+
var crypto$1 = require('crypto');
|
|
11
12
|
var pify = _interopDefault(require('pify'));
|
|
12
13
|
var ignore = _interopDefault(require('ignore'));
|
|
13
14
|
var cleanGitRef = _interopDefault(require('clean-git-ref'));
|
|
@@ -3368,6 +3369,19 @@ function readPackIndex({
|
|
|
3368
3369
|
return p
|
|
3369
3370
|
}
|
|
3370
3371
|
|
|
3372
|
+
const SHA1_CHUNK_SIZE = 8 * 1024 * 1024;
|
|
3373
|
+
|
|
3374
|
+
async function shasumRange(
|
|
3375
|
+
buffer,
|
|
3376
|
+
{ start = 0, end = buffer.length } = {}
|
|
3377
|
+
) {
|
|
3378
|
+
const hash = crypto$1.createHash('sha1');
|
|
3379
|
+
for (let i = start; i < end; i += SHA1_CHUNK_SIZE) {
|
|
3380
|
+
hash.update(buffer.subarray(i, Math.min(i + SHA1_CHUNK_SIZE, end)));
|
|
3381
|
+
}
|
|
3382
|
+
return hash.digest('hex')
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3371
3385
|
async function readObjectPacked({
|
|
3372
3386
|
fs,
|
|
3373
3387
|
cache,
|
|
@@ -3421,11 +3435,12 @@ async function readObjectPacked({
|
|
|
3421
3435
|
)
|
|
3422
3436
|
}
|
|
3423
3437
|
|
|
3424
|
-
// 2. Deep Integrity Check: Calculate actual SHA-1 of packfile payload
|
|
3425
|
-
//
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3438
|
+
// 2. Deep Integrity Check: Calculate actual SHA-1 of packfile payload.
|
|
3439
|
+
// The Node package build swaps in a chunked implementation for large packs.
|
|
3440
|
+
const actualPayloadSha = await shasumRange(pack, {
|
|
3441
|
+
start: 0,
|
|
3442
|
+
end: pack.length - 20,
|
|
3443
|
+
});
|
|
3429
3444
|
if (actualPayloadSha !== expectedShaFromIndex) {
|
|
3430
3445
|
throw new InternalError(
|
|
3431
3446
|
`Packfile payload corrupted: calculated ${actualPayloadSha} but expected ${expectedShaFromIndex}. The packfile may have been tampered with.`
|
|
@@ -7046,7 +7061,7 @@ async function _checkout({
|
|
|
7046
7061
|
await GitIndexManager.acquire(
|
|
7047
7062
|
{ fs, gitdir, cache, allowUnmerged: true },
|
|
7048
7063
|
async function (index) {
|
|
7049
|
-
await Promise.
|
|
7064
|
+
const settled = await Promise.allSettled(
|
|
7050
7065
|
ops
|
|
7051
7066
|
.filter(
|
|
7052
7067
|
([method]) =>
|
|
@@ -7057,66 +7072,76 @@ async function _checkout({
|
|
|
7057
7072
|
)
|
|
7058
7073
|
.map(async function ([method, fullpath, oid, mode, chmod]) {
|
|
7059
7074
|
const filepath = `${dir}/${fullpath}`;
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
gitdir,
|
|
7066
|
-
oid,
|
|
7067
|
-
});
|
|
7068
|
-
if (chmod) {
|
|
7069
|
-
// Note: the mode option of fs.write only works when creating files,
|
|
7070
|
-
// not updating them. Since the `fs` plugin doesn't expose `chmod` this
|
|
7071
|
-
// is our only option.
|
|
7072
|
-
await fs.rm(filepath);
|
|
7073
|
-
}
|
|
7074
|
-
if (mode === 0o100644) {
|
|
7075
|
-
// regular file
|
|
7076
|
-
await fs.write(filepath, object);
|
|
7077
|
-
} else if (mode === 0o100755) {
|
|
7078
|
-
// executable file
|
|
7079
|
-
await fs.write(filepath, object, { mode: 0o777 });
|
|
7080
|
-
} else if (mode === 0o120000) {
|
|
7081
|
-
// symlink
|
|
7082
|
-
await fs.writelink(filepath, object);
|
|
7083
|
-
} else {
|
|
7084
|
-
throw new InternalError(
|
|
7085
|
-
`Invalid mode 0o${mode.toString(
|
|
7086
|
-
8
|
|
7087
|
-
)} detected in blob ${oid}`
|
|
7088
|
-
)
|
|
7089
|
-
}
|
|
7090
|
-
}
|
|
7091
|
-
|
|
7092
|
-
const stats = await fs.lstat(filepath);
|
|
7093
|
-
// We can't trust the executable bit returned by lstat on Windows,
|
|
7094
|
-
// so we need to preserve this value from the TREE.
|
|
7095
|
-
// TODO: Figure out how git handles this internally.
|
|
7096
|
-
if (mode === 0o100755) {
|
|
7097
|
-
stats.mode = 0o755;
|
|
7098
|
-
}
|
|
7099
|
-
// Submodules are present in the git index but use a unique mode different from trees
|
|
7100
|
-
if (method === 'mkdir-index') {
|
|
7101
|
-
stats.mode = 0o160000;
|
|
7102
|
-
}
|
|
7103
|
-
index.insert({
|
|
7104
|
-
filepath: fullpath,
|
|
7105
|
-
stats,
|
|
7075
|
+
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7076
|
+
const { object } = await _readObject({
|
|
7077
|
+
fs,
|
|
7078
|
+
cache,
|
|
7079
|
+
gitdir,
|
|
7106
7080
|
oid,
|
|
7107
7081
|
});
|
|
7108
|
-
if (
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
});
|
|
7082
|
+
if (chmod) {
|
|
7083
|
+
// Note: the mode option of fs.write only works when creating files,
|
|
7084
|
+
// not updating them. Since the `fs` plugin doesn't expose `chmod` this
|
|
7085
|
+
// is our only option.
|
|
7086
|
+
await fs.rm(filepath);
|
|
7114
7087
|
}
|
|
7115
|
-
|
|
7116
|
-
|
|
7088
|
+
if (mode === 0o100644) {
|
|
7089
|
+
// regular file
|
|
7090
|
+
await fs.write(filepath, object);
|
|
7091
|
+
} else if (mode === 0o100755) {
|
|
7092
|
+
// executable file
|
|
7093
|
+
await fs.write(filepath, object, { mode: 0o777 });
|
|
7094
|
+
} else if (mode === 0o120000) {
|
|
7095
|
+
// symlink
|
|
7096
|
+
await fs.writelink(filepath, object);
|
|
7097
|
+
} else {
|
|
7098
|
+
throw new InternalError(
|
|
7099
|
+
`Invalid mode 0o${mode.toString(
|
|
7100
|
+
8
|
|
7101
|
+
)} detected in blob ${oid}`
|
|
7102
|
+
)
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
|
|
7106
|
+
const stats = await fs.lstat(filepath);
|
|
7107
|
+
// We can't trust the executable bit returned by lstat on Windows,
|
|
7108
|
+
// so we need to preserve this value from the TREE.
|
|
7109
|
+
// TODO: Figure out how git handles this internally.
|
|
7110
|
+
if (mode === 0o100755) {
|
|
7111
|
+
stats.mode = 0o755;
|
|
7112
|
+
}
|
|
7113
|
+
// Submodules are present in the git index but use a unique mode different from trees
|
|
7114
|
+
if (method === 'mkdir-index') {
|
|
7115
|
+
stats.mode = 0o160000;
|
|
7116
|
+
}
|
|
7117
|
+
index.insert({
|
|
7118
|
+
filepath: fullpath,
|
|
7119
|
+
stats,
|
|
7120
|
+
oid,
|
|
7121
|
+
});
|
|
7122
|
+
if (onProgress) {
|
|
7123
|
+
await onProgress({
|
|
7124
|
+
phase: 'Updating workdir',
|
|
7125
|
+
loaded: ++count,
|
|
7126
|
+
total,
|
|
7127
|
+
});
|
|
7117
7128
|
}
|
|
7118
7129
|
})
|
|
7119
7130
|
);
|
|
7131
|
+
const rejections = [];
|
|
7132
|
+
for (const result of settled) {
|
|
7133
|
+
if (result.status === 'rejected') {
|
|
7134
|
+
rejections.push(result.reason);
|
|
7135
|
+
// eslint-disable-next-line no-console
|
|
7136
|
+
console.error(
|
|
7137
|
+
'[isomorphic-git checkout] task rejected:',
|
|
7138
|
+
result.reason?.stack ?? result.reason
|
|
7139
|
+
);
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
7142
|
+
if (rejections.length > 0) {
|
|
7143
|
+
throw new MultipleGitError(rejections)
|
|
7144
|
+
}
|
|
7120
7145
|
}
|
|
7121
7146
|
);
|
|
7122
7147
|
}
|
|
@@ -7485,27 +7510,34 @@ async function updateWorkingDir(
|
|
|
7485
7510
|
|
|
7486
7511
|
async function batchAllSettled(operationName, tasks, onProgress, batchSize) {
|
|
7487
7512
|
const results = [];
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7513
|
+
const rejections = [];
|
|
7514
|
+
for (let i = 0; i < tasks.length; i += batchSize) {
|
|
7515
|
+
const batch = tasks.slice(i, i + batchSize).map(task => task());
|
|
7516
|
+
const batchResults = await Promise.allSettled(batch);
|
|
7517
|
+
batchResults.forEach(result => {
|
|
7518
|
+
if (result.status === 'fulfilled') {
|
|
7519
|
+
results.push(result.value);
|
|
7520
|
+
} else {
|
|
7521
|
+
rejections.push(result.reason);
|
|
7522
|
+
// eslint-disable-next-line no-console
|
|
7523
|
+
console.error(
|
|
7524
|
+
`[isomorphic-git ${operationName}] task rejected:`,
|
|
7525
|
+
result.reason?.stack ?? result.reason
|
|
7526
|
+
);
|
|
7501
7527
|
}
|
|
7528
|
+
});
|
|
7529
|
+
if (onProgress) {
|
|
7530
|
+
await onProgress({
|
|
7531
|
+
phase: 'Updating workdir',
|
|
7532
|
+
loaded: i + batch.length,
|
|
7533
|
+
total: tasks.length,
|
|
7534
|
+
});
|
|
7502
7535
|
}
|
|
7503
|
-
|
|
7504
|
-
return results
|
|
7505
|
-
} catch (error) {
|
|
7506
|
-
console.error(`Error during ${operationName}: ${error}`);
|
|
7507
7536
|
}
|
|
7508
7537
|
|
|
7538
|
+
if (rejections.length > 0) {
|
|
7539
|
+
throw new MultipleGitError(rejections)
|
|
7540
|
+
}
|
|
7509
7541
|
return results
|
|
7510
7542
|
}
|
|
7511
7543
|
|
|
@@ -9311,8 +9343,8 @@ function filterCapabilities(server, client) {
|
|
|
9311
9343
|
|
|
9312
9344
|
const pkg = {
|
|
9313
9345
|
name: 'isomorphic-git',
|
|
9314
|
-
version: '1.37.
|
|
9315
|
-
agent: 'git/isomorphic-git@1.37.
|
|
9346
|
+
version: '1.37.6',
|
|
9347
|
+
agent: 'git/isomorphic-git@1.37.6',
|
|
9316
9348
|
};
|
|
9317
9349
|
|
|
9318
9350
|
class FIFO {
|
package/index.js
CHANGED
|
@@ -3362,6 +3362,13 @@ function readPackIndex({
|
|
|
3362
3362
|
return p
|
|
3363
3363
|
}
|
|
3364
3364
|
|
|
3365
|
+
async function shasumRange(
|
|
3366
|
+
buffer,
|
|
3367
|
+
{ start = 0, end = buffer.length } = {}
|
|
3368
|
+
) {
|
|
3369
|
+
return shasum(buffer.subarray(start, end))
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3365
3372
|
async function readObjectPacked({
|
|
3366
3373
|
fs,
|
|
3367
3374
|
cache,
|
|
@@ -3415,11 +3422,12 @@ async function readObjectPacked({
|
|
|
3415
3422
|
)
|
|
3416
3423
|
}
|
|
3417
3424
|
|
|
3418
|
-
// 2. Deep Integrity Check: Calculate actual SHA-1 of packfile payload
|
|
3419
|
-
//
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3425
|
+
// 2. Deep Integrity Check: Calculate actual SHA-1 of packfile payload.
|
|
3426
|
+
// The Node package build swaps in a chunked implementation for large packs.
|
|
3427
|
+
const actualPayloadSha = await shasumRange(pack, {
|
|
3428
|
+
start: 0,
|
|
3429
|
+
end: pack.length - 20,
|
|
3430
|
+
});
|
|
3423
3431
|
if (actualPayloadSha !== expectedShaFromIndex) {
|
|
3424
3432
|
throw new InternalError(
|
|
3425
3433
|
`Packfile payload corrupted: calculated ${actualPayloadSha} but expected ${expectedShaFromIndex}. The packfile may have been tampered with.`
|
|
@@ -7040,7 +7048,7 @@ async function _checkout({
|
|
|
7040
7048
|
await GitIndexManager.acquire(
|
|
7041
7049
|
{ fs, gitdir, cache, allowUnmerged: true },
|
|
7042
7050
|
async function (index) {
|
|
7043
|
-
await Promise.
|
|
7051
|
+
const settled = await Promise.allSettled(
|
|
7044
7052
|
ops
|
|
7045
7053
|
.filter(
|
|
7046
7054
|
([method]) =>
|
|
@@ -7051,66 +7059,76 @@ async function _checkout({
|
|
|
7051
7059
|
)
|
|
7052
7060
|
.map(async function ([method, fullpath, oid, mode, chmod]) {
|
|
7053
7061
|
const filepath = `${dir}/${fullpath}`;
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
gitdir,
|
|
7060
|
-
oid,
|
|
7061
|
-
});
|
|
7062
|
-
if (chmod) {
|
|
7063
|
-
// Note: the mode option of fs.write only works when creating files,
|
|
7064
|
-
// not updating them. Since the `fs` plugin doesn't expose `chmod` this
|
|
7065
|
-
// is our only option.
|
|
7066
|
-
await fs.rm(filepath);
|
|
7067
|
-
}
|
|
7068
|
-
if (mode === 0o100644) {
|
|
7069
|
-
// regular file
|
|
7070
|
-
await fs.write(filepath, object);
|
|
7071
|
-
} else if (mode === 0o100755) {
|
|
7072
|
-
// executable file
|
|
7073
|
-
await fs.write(filepath, object, { mode: 0o777 });
|
|
7074
|
-
} else if (mode === 0o120000) {
|
|
7075
|
-
// symlink
|
|
7076
|
-
await fs.writelink(filepath, object);
|
|
7077
|
-
} else {
|
|
7078
|
-
throw new InternalError(
|
|
7079
|
-
`Invalid mode 0o${mode.toString(
|
|
7080
|
-
8
|
|
7081
|
-
)} detected in blob ${oid}`
|
|
7082
|
-
)
|
|
7083
|
-
}
|
|
7084
|
-
}
|
|
7085
|
-
|
|
7086
|
-
const stats = await fs.lstat(filepath);
|
|
7087
|
-
// We can't trust the executable bit returned by lstat on Windows,
|
|
7088
|
-
// so we need to preserve this value from the TREE.
|
|
7089
|
-
// TODO: Figure out how git handles this internally.
|
|
7090
|
-
if (mode === 0o100755) {
|
|
7091
|
-
stats.mode = 0o755;
|
|
7092
|
-
}
|
|
7093
|
-
// Submodules are present in the git index but use a unique mode different from trees
|
|
7094
|
-
if (method === 'mkdir-index') {
|
|
7095
|
-
stats.mode = 0o160000;
|
|
7096
|
-
}
|
|
7097
|
-
index.insert({
|
|
7098
|
-
filepath: fullpath,
|
|
7099
|
-
stats,
|
|
7062
|
+
if (method !== 'create-index' && method !== 'mkdir-index') {
|
|
7063
|
+
const { object } = await _readObject({
|
|
7064
|
+
fs,
|
|
7065
|
+
cache,
|
|
7066
|
+
gitdir,
|
|
7100
7067
|
oid,
|
|
7101
7068
|
});
|
|
7102
|
-
if (
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7069
|
+
if (chmod) {
|
|
7070
|
+
// Note: the mode option of fs.write only works when creating files,
|
|
7071
|
+
// not updating them. Since the `fs` plugin doesn't expose `chmod` this
|
|
7072
|
+
// is our only option.
|
|
7073
|
+
await fs.rm(filepath);
|
|
7074
|
+
}
|
|
7075
|
+
if (mode === 0o100644) {
|
|
7076
|
+
// regular file
|
|
7077
|
+
await fs.write(filepath, object);
|
|
7078
|
+
} else if (mode === 0o100755) {
|
|
7079
|
+
// executable file
|
|
7080
|
+
await fs.write(filepath, object, { mode: 0o777 });
|
|
7081
|
+
} else if (mode === 0o120000) {
|
|
7082
|
+
// symlink
|
|
7083
|
+
await fs.writelink(filepath, object);
|
|
7084
|
+
} else {
|
|
7085
|
+
throw new InternalError(
|
|
7086
|
+
`Invalid mode 0o${mode.toString(
|
|
7087
|
+
8
|
|
7088
|
+
)} detected in blob ${oid}`
|
|
7089
|
+
)
|
|
7108
7090
|
}
|
|
7109
|
-
}
|
|
7110
|
-
|
|
7091
|
+
}
|
|
7092
|
+
|
|
7093
|
+
const stats = await fs.lstat(filepath);
|
|
7094
|
+
// We can't trust the executable bit returned by lstat on Windows,
|
|
7095
|
+
// so we need to preserve this value from the TREE.
|
|
7096
|
+
// TODO: Figure out how git handles this internally.
|
|
7097
|
+
if (mode === 0o100755) {
|
|
7098
|
+
stats.mode = 0o755;
|
|
7099
|
+
}
|
|
7100
|
+
// Submodules are present in the git index but use a unique mode different from trees
|
|
7101
|
+
if (method === 'mkdir-index') {
|
|
7102
|
+
stats.mode = 0o160000;
|
|
7103
|
+
}
|
|
7104
|
+
index.insert({
|
|
7105
|
+
filepath: fullpath,
|
|
7106
|
+
stats,
|
|
7107
|
+
oid,
|
|
7108
|
+
});
|
|
7109
|
+
if (onProgress) {
|
|
7110
|
+
await onProgress({
|
|
7111
|
+
phase: 'Updating workdir',
|
|
7112
|
+
loaded: ++count,
|
|
7113
|
+
total,
|
|
7114
|
+
});
|
|
7111
7115
|
}
|
|
7112
7116
|
})
|
|
7113
7117
|
);
|
|
7118
|
+
const rejections = [];
|
|
7119
|
+
for (const result of settled) {
|
|
7120
|
+
if (result.status === 'rejected') {
|
|
7121
|
+
rejections.push(result.reason);
|
|
7122
|
+
// eslint-disable-next-line no-console
|
|
7123
|
+
console.error(
|
|
7124
|
+
'[isomorphic-git checkout] task rejected:',
|
|
7125
|
+
result.reason?.stack ?? result.reason
|
|
7126
|
+
);
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
7129
|
+
if (rejections.length > 0) {
|
|
7130
|
+
throw new MultipleGitError(rejections)
|
|
7131
|
+
}
|
|
7114
7132
|
}
|
|
7115
7133
|
);
|
|
7116
7134
|
}
|
|
@@ -7479,27 +7497,34 @@ async function updateWorkingDir(
|
|
|
7479
7497
|
|
|
7480
7498
|
async function batchAllSettled(operationName, tasks, onProgress, batchSize) {
|
|
7481
7499
|
const results = [];
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7500
|
+
const rejections = [];
|
|
7501
|
+
for (let i = 0; i < tasks.length; i += batchSize) {
|
|
7502
|
+
const batch = tasks.slice(i, i + batchSize).map(task => task());
|
|
7503
|
+
const batchResults = await Promise.allSettled(batch);
|
|
7504
|
+
batchResults.forEach(result => {
|
|
7505
|
+
if (result.status === 'fulfilled') {
|
|
7506
|
+
results.push(result.value);
|
|
7507
|
+
} else {
|
|
7508
|
+
rejections.push(result.reason);
|
|
7509
|
+
// eslint-disable-next-line no-console
|
|
7510
|
+
console.error(
|
|
7511
|
+
`[isomorphic-git ${operationName}] task rejected:`,
|
|
7512
|
+
result.reason?.stack ?? result.reason
|
|
7513
|
+
);
|
|
7495
7514
|
}
|
|
7515
|
+
});
|
|
7516
|
+
if (onProgress) {
|
|
7517
|
+
await onProgress({
|
|
7518
|
+
phase: 'Updating workdir',
|
|
7519
|
+
loaded: i + batch.length,
|
|
7520
|
+
total: tasks.length,
|
|
7521
|
+
});
|
|
7496
7522
|
}
|
|
7497
|
-
|
|
7498
|
-
return results
|
|
7499
|
-
} catch (error) {
|
|
7500
|
-
console.error(`Error during ${operationName}: ${error}`);
|
|
7501
7523
|
}
|
|
7502
7524
|
|
|
7525
|
+
if (rejections.length > 0) {
|
|
7526
|
+
throw new MultipleGitError(rejections)
|
|
7527
|
+
}
|
|
7503
7528
|
return results
|
|
7504
7529
|
}
|
|
7505
7530
|
|
|
@@ -9305,8 +9330,8 @@ function filterCapabilities(server, client) {
|
|
|
9305
9330
|
|
|
9306
9331
|
const pkg = {
|
|
9307
9332
|
name: 'isomorphic-git',
|
|
9308
|
-
version: '1.37.
|
|
9309
|
-
agent: 'git/isomorphic-git@1.37.
|
|
9333
|
+
version: '1.37.6',
|
|
9334
|
+
agent: 'git/isomorphic-git@1.37.6',
|
|
9310
9335
|
};
|
|
9311
9336
|
|
|
9312
9337
|
class FIFO {
|