scanoss 0.39.0 → 0.40.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/CHANGELOG.md +8 -0
- package/build/main/cli/commands/wfp.js +3 -3
- package/build/main/sdk/scanner/Scannable/ScannableItem.d.ts +2 -1
- package/build/main/sdk/scanner/Scannable/ScannableItem.js +3 -2
- package/build/main/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +30 -15
- package/build/main/tsconfig.tsbuildinfo +1 -1
- package/build/module/cli/commands/wfp.js +3 -3
- package/build/module/sdk/scanner/Scannable/ScannableItem.d.ts +2 -1
- package/build/module/sdk/scanner/Scannable/ScannableItem.js +4 -2
- package/build/module/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +30 -15
- package/build/module/tsconfig.module.tsbuildinfo +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
|
+
## [0.40.0] (2026-04-28)
|
|
7
|
+
### Fixed
|
|
8
|
+
- `WfpCalculator` no longer crashes with `RangeError: Invalid array length` when fingerprinting large binary files.
|
|
9
|
+
- `scanoss-js wfp` CLI now uses `ScanFilter` instead of `DependencyFilter` when building the file list
|
|
10
|
+
### Changed
|
|
11
|
+
- `WfpCalculator` now detects binary files via `isBinaryFileSync`. Binary files emit only the `file=` MD5 line.
|
|
6
12
|
|
|
7
13
|
## [0.39.0] (2026-04-23)
|
|
8
14
|
### Added
|
|
@@ -299,3 +305,5 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
299
305
|
### [0.37.0](https://github.com/scanoss/scanoss.js/compare/v0.36.0...v0.37.0) (2026-03-02)
|
|
300
306
|
### [0.38.0](https://github.com/scanoss/scanoss.js/compare/v0.37.0...v0.38.0) (2026-03-12)
|
|
301
307
|
### [0.38.1](https://github.com/scanoss/scanoss.js/compare/v0.38.0...v0.38.1) (2026-04-08)
|
|
308
|
+
### [0.39.0](https://github.com/scanoss/scanoss.js/compare/v0.38.1...v0.39.0) (2026-04-23)
|
|
309
|
+
### [0.40.0](https://github.com/scanoss/scanoss.js/compare/v0.39.0...v0.40.0) (2026-04-28)
|
|
@@ -10,7 +10,7 @@ const helpers_1 = require("./helpers");
|
|
|
10
10
|
const ScannerTypes_1 = require("../../sdk/scanner/ScannerTypes");
|
|
11
11
|
const WfpCalculator_1 = require("../../sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator");
|
|
12
12
|
const Tree_1 = require("../../sdk/tree/Tree");
|
|
13
|
-
const
|
|
13
|
+
const ScanFilter_1 = require("../../sdk/tree/Filters/ScanFilter");
|
|
14
14
|
async function wfpHandler(rootPath, options) {
|
|
15
15
|
rootPath = rootPath.replace(/\/$/, ''); // Remove trailing slash if exists
|
|
16
16
|
rootPath = rootPath.replace(/^\./, process.env.PWD); // Convert relative path to absolute path.
|
|
@@ -20,7 +20,7 @@ async function wfpHandler(rootPath, options) {
|
|
|
20
20
|
if (pathIsFolder) {
|
|
21
21
|
const tree = new Tree_1.Tree(rootPath);
|
|
22
22
|
tree.build();
|
|
23
|
-
filesToFingerprint = tree.getFileList(new
|
|
23
|
+
filesToFingerprint = tree.getFileList(new ScanFilter_1.ScanFilter(""));
|
|
24
24
|
}
|
|
25
25
|
else {
|
|
26
26
|
filesToFingerprint.push(rootPath);
|
|
@@ -51,4 +51,4 @@ async function wfpHandler(rootPath, options) {
|
|
|
51
51
|
wfpInput.winnowingMode = ScannerTypes_1.WinnowingMode.FULL_WINNOWING_HPSM;
|
|
52
52
|
await wfpCalculator.start(wfpInput);
|
|
53
53
|
}
|
|
54
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
54
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ZwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NsaS9jb21tYW5kcy93ZnAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFhQSxnQ0E4Q0M7QUEzREQsNENBQW9CO0FBRXBCLGdFQUF1QztBQUV2Qyx1Q0FBcUM7QUFDckMsaUVBQThFO0FBRTlFLDZGQUEwRjtBQUUxRiw4Q0FBMkM7QUFDM0Msa0VBQStEO0FBR3hELEtBQUssVUFBVSxVQUFVLENBQUMsUUFBZ0IsRUFBRSxPQUFZO0lBRTdELFFBQVEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFFLGtDQUFrQztJQUMzRSxRQUFRLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFFLDBDQUEwQztJQUNoRyxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUEsa0JBQVEsRUFBQyxRQUFRLENBQUMsQ0FBQztJQUM5QyxNQUFNLGFBQWEsR0FBRyxJQUFJLDZCQUFhLEVBQUUsQ0FBQztJQUUxQyxJQUFJLGtCQUFrQixHQUFhLEVBQUUsQ0FBQztJQUN0QyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2pCLE1BQU0sSUFBSSxHQUFHLElBQUksV0FBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNiLGtCQUFrQixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSx1QkFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDNUQsQ0FBQztTQUFNLENBQUM7UUFDTixrQkFBa0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDbkMsQ0FBQztJQUdELE1BQU0sT0FBTyxHQUFHLEVBQUUsTUFBTSxFQUFFLHlGQUF5RixFQUFFLENBQUM7SUFDdEgsTUFBTSxJQUFJLEdBQUcsSUFBSSxzQkFBVyxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsc0JBQVcsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDcEYsSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFekMsSUFBSSxZQUFZLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLGFBQWEsQ0FBQyxFQUFFLENBQUMsNEJBQWEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLGtCQUFzQyxFQUFFLEVBQUU7UUFDL0YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQywyQkFBMkIsRUFBRSxDQUFDLENBQUM7UUFDakUsWUFBWSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUUsa0JBQWtCLENBQUMsVUFBVSxFQUFFLENBQUUsQ0FBQztJQUN4RSxDQUFDLENBQUMsQ0FBQztJQUVILElBQUksT0FBTyxDQUFDLE9BQU87UUFDakIsYUFBYSxDQUFDLEVBQUUsQ0FBQyw0QkFBYSxDQUFDLFlBQVksRUFBRSxDQUFDLEdBQVcsRUFBRSxFQUFFO1lBQzNELE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDckIsQ0FBQyxDQUFDLENBQUM7SUFFTCxhQUFhLENBQUMsRUFBRSxDQUFDLDRCQUFhLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxFQUFFO1FBQ3RELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNaLElBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2xCLFlBQUUsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUNqRCxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQXNCLEVBQUMsUUFBUSxFQUFFLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQTtJQUN2SCxJQUFHLE9BQU8sQ0FBQyxJQUFJO1FBQUUsUUFBUSxDQUFDLGFBQWEsR0FBRyw0QkFBYSxDQUFDLG1CQUFtQixDQUFDO0lBQzVFLE1BQU0sYUFBYSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUd0QyxDQUFDIn0=
|
|
@@ -6,7 +6,8 @@ export declare class ScannableItem {
|
|
|
6
6
|
private fingerprint;
|
|
7
7
|
private maxSizeWfp;
|
|
8
8
|
private lineOffset;
|
|
9
|
-
|
|
9
|
+
private isBinary;
|
|
10
|
+
constructor(content: Buffer, contentSource: string, winnowingMode: any, maxSizeWfp: number, isBinary?: boolean);
|
|
10
11
|
getContent(): Buffer<ArrayBufferLike>;
|
|
11
12
|
getContentSource(): string;
|
|
12
13
|
getFingerprint(): any;
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ScannableItem = void 0;
|
|
4
4
|
class ScannableItem {
|
|
5
|
-
constructor(content, contentSource, winnowingMode, maxSizeWfp) {
|
|
5
|
+
constructor(content, contentSource, winnowingMode, maxSizeWfp, isBinary = false) {
|
|
6
6
|
this.contentSource = contentSource;
|
|
7
7
|
this.content = content;
|
|
8
8
|
this.winnowingMode = winnowingMode;
|
|
9
9
|
this.maxSizeWfp = maxSizeWfp;
|
|
10
10
|
this.lineOffset = 0;
|
|
11
|
+
this.isBinary = isBinary;
|
|
11
12
|
}
|
|
12
13
|
getContent() {
|
|
13
14
|
return this.content;
|
|
@@ -32,4 +33,4 @@ class ScannableItem {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
exports.ScannableItem = ScannableItem;
|
|
35
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2Nhbm5hYmxlSXRlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9zZGsvc2Nhbm5lci9TY2FubmFibGUvU2Nhbm5hYmxlSXRlbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxNQUFhLGFBQWE7SUFleEIsWUFBWSxPQUFlLEVBQUUsYUFBcUIsRUFBRSxhQUFrQixFQUFFLFVBQWtCLEVBQUUsUUFBUSxHQUFHLEtBQUs7UUFDMUcsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDbkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDbkMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFDcEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDM0IsQ0FBQztJQUVNLFVBQVU7UUFDZixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVNLGdCQUFnQjtRQUNyQixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDNUIsQ0FBQztJQUVNLGNBQWM7UUFDbkIsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFCLENBQUM7SUFFTSxnQkFBZ0I7UUFDckIsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQzVCLENBQUM7SUFFTSxhQUFhO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6QixDQUFDO0lBRU0sYUFBYSxDQUFDLE1BQWM7UUFDakMsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUM7SUFDM0IsQ0FBQztJQUVNLGFBQWE7UUFDbEIsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7Q0FDRjtBQW5ERCxzQ0FtREMifQ==
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WfpCalculator = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const isbinaryfile_1 = require("isbinaryfile");
|
|
8
9
|
const worker_threads_1 = require("worker_threads");
|
|
9
10
|
const ScannableItem_1 = require("../../Scannable/ScannableItem");
|
|
10
11
|
const ScannerCfg_1 = require("../../ScannerCfg");
|
|
@@ -22,18 +23,21 @@ parentPort.on('message', async (scannableItem) => {
|
|
|
22
23
|
fingerprint = wfp_for_content(
|
|
23
24
|
scannableItem.content,
|
|
24
25
|
scannableItem.contentSource,
|
|
25
|
-
scannableItem.maxSizeWfp
|
|
26
|
+
scannableItem.maxSizeWfp,
|
|
27
|
+
scannableItem.isBinary
|
|
26
28
|
);
|
|
27
29
|
} else if (scannableItem.winnowingMode === "FULL_WINNOWING_HPSM") {
|
|
28
30
|
fingerprint = wfp_hpsm_for_content(
|
|
29
31
|
scannableItem.content,
|
|
30
32
|
scannableItem.contentSource,
|
|
31
|
-
scannableItem.maxSizeWfp
|
|
33
|
+
scannableItem.maxSizeWfp,
|
|
34
|
+
scannableItem.isBinary
|
|
32
35
|
);
|
|
33
36
|
} else if (scannableItem.winnowingMode === "WINNOWING_ONLY_MD5") {
|
|
34
37
|
fingerprint = wfp_only_md5(
|
|
35
38
|
scannableItem.content,
|
|
36
|
-
scannableItem.contentSource
|
|
39
|
+
scannableItem.contentSource,
|
|
40
|
+
scannableItem.isBinary
|
|
37
41
|
);
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -296,18 +300,25 @@ function join_wfp_hpsm(wfp, hpsm) {
|
|
|
296
300
|
* @param {Buffer} content
|
|
297
301
|
* @param {string} contentSource
|
|
298
302
|
* @param {number} maxSize
|
|
303
|
+
* @param {boolean} isBinary When true, HPSM and snippet winnowing are skipped (binary content has no line/code semantics)
|
|
299
304
|
* @returns {string}
|
|
300
305
|
*/
|
|
301
|
-
function wfp_hpsm_for_content(content, contentSource, maxSize) {
|
|
302
|
-
let wfp = wfp_for_content(content, contentSource, maxSize)
|
|
306
|
+
function wfp_hpsm_for_content(content, contentSource, maxSize, isBinary) {
|
|
307
|
+
let wfp = wfp_for_content(content, contentSource, maxSize, isBinary)
|
|
308
|
+
if (isBinary) return truncate_string(wfp, maxSize)
|
|
303
309
|
let hpsm = calc_hpsm(content) //Returns a string
|
|
304
310
|
let wfp_hpsm_joined = join_wfp_hpsm(wfp, hpsm)
|
|
305
311
|
return truncate_string(wfp_hpsm_joined, maxSize)
|
|
306
312
|
}
|
|
307
313
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
314
|
+
// Snippet winnowing and HPSM are line/code semantics — meaningless on
|
|
315
|
+
// binary content (random bytes produce noise grams). Binary files emit
|
|
316
|
+
// only the file= MD5 line, matching the behavior of WINNOWING_ONLY_MD5.
|
|
317
|
+
function wfp_for_content(content, contentSource, maxSize, isBinary) {
|
|
318
|
+
let wfp = wfp_only_md5(content, contentSource, isBinary);
|
|
319
|
+
if (!isBinary) {
|
|
320
|
+
wfp += calc_wfp(content, maxSize);
|
|
321
|
+
}
|
|
311
322
|
return wfp;
|
|
312
323
|
}
|
|
313
324
|
|
|
@@ -416,14 +427,17 @@ function calculate_opposite_line_ending_hash(contents) {
|
|
|
416
427
|
return crypto.createHash('md5').update(opposite_contents).digest('hex');
|
|
417
428
|
}
|
|
418
429
|
|
|
419
|
-
function wfp_only_md5(contents, contentSource) {
|
|
430
|
+
function wfp_only_md5(contents, contentSource, isBinary) {
|
|
420
431
|
const file_md5 = crypto.createHash('md5').update(contents).digest('hex');
|
|
421
432
|
let wfp = 'file=' + String(file_md5) + ',' + String(contents.length) + ',' + String(contentSource)+ String.fromCharCode(10);
|
|
422
433
|
|
|
423
|
-
//
|
|
424
|
-
|
|
425
|
-
if (
|
|
426
|
-
|
|
434
|
+
// fh2 has no meaning on binary content (no line endings to flip) and the
|
|
435
|
+
// normalization loop blows past V8 limits on large buffers.
|
|
436
|
+
if (!isBinary) {
|
|
437
|
+
const opposite_hash = calculate_opposite_line_ending_hash(contents);
|
|
438
|
+
if (opposite_hash !== null) {
|
|
439
|
+
wfp += 'fh2=' + String(opposite_hash) + String.fromCharCode(10);
|
|
440
|
+
}
|
|
427
441
|
}
|
|
428
442
|
|
|
429
443
|
return wfp;
|
|
@@ -559,10 +573,11 @@ class WfpCalculator extends WfpProvider_1.WfpProvider {
|
|
|
559
573
|
const path = this.fileList[this.fileListIndex];
|
|
560
574
|
const contentSource = path.replace(`${this.folderRoot}`, '');
|
|
561
575
|
const content = await this.readFile(path);
|
|
576
|
+
const isBinary = content.length > 0 && (0, isbinaryfile_1.isBinaryFileSync)(path);
|
|
562
577
|
this.fileListIndex += 1;
|
|
563
578
|
if (!(this.fileListIndex % this.scannerCfg.WINNOWING_REPORT_STATUS_AFTER_X))
|
|
564
579
|
this.emit(ScannerTypes_1.ScannerEvents.WINNOWING_STATUS, this.scannerCfg.WINNOWING_REPORT_STATUS_AFTER_X);
|
|
565
|
-
const scannable = new ScannableItem_1.ScannableItem(content, contentSource, this.winnowingMode, this.scannerCfg.WFP_FILE_MAX_SIZE);
|
|
580
|
+
const scannable = new ScannableItem_1.ScannableItem(content, contentSource, this.winnowingMode, this.scannerCfg.WFP_FILE_MAX_SIZE, isBinary);
|
|
566
581
|
if (this.headerFilter && content.length > 0) {
|
|
567
582
|
const lineOffset = this.headerFilter.filter(path, content.toString('utf-8'));
|
|
568
583
|
scannable.setLineOffset(lineOffset);
|
|
@@ -640,4 +655,4 @@ class WfpCalculator extends WfpProvider_1.WfpProvider {
|
|
|
640
655
|
}
|
|
641
656
|
}
|
|
642
657
|
exports.WfpCalculator = WfpCalculator;
|
|
643
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
658
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ZwQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9zZGsvc2Nhbm5lci9XZnBQcm92aWRlci9XZnBDYWxjdWxhdG9yL1dmcENhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLCtDQUFnRDtBQUNoRCxtREFBd0M7QUFFeEMsaUVBQThEO0FBQzlELGlEQUE4QztBQUM5QyxxREFBZ0Y7QUFFaEYsOERBQTJEO0FBQzNELGdEQUFnRTtBQUNoRSxpREFBcUU7QUFFckUsTUFBTSxZQUFZLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBdWZwQixDQUFDO0FBRUYsTUFBYSxhQUFjLFNBQVEseUJBQVc7SUFTNUMsWUFBWSxVQUFVLEdBQUcsSUFBSSx1QkFBVSxFQUFFO1FBQ3ZDLEtBQUss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
|