@zip.js/zip.js 2.5.20 → 2.5.23
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/cli-deno/mc-zip.js +10 -4
- package/dist/zip-fs-full.js +48 -53
- package/dist/zip-fs-full.min.js +1 -1
- package/dist/zip-fs.js +48 -53
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-full.js +48 -53
- package/dist/zip-full.min.js +1 -1
- package/dist/zip-no-worker-deflate.min.js +1 -1
- package/dist/zip-no-worker-inflate.min.js +1 -1
- package/dist/zip-no-worker.min.js +1 -1
- package/dist/zip.js +48 -53
- package/dist/zip.min.js +1 -1
- package/index.d.ts +6 -0
- package/lib/core/zip-reader.js +16 -5
- package/lib/core/zip-writer.js +32 -48
- package/lib/zip-fs.js +3 -3
- package/lib/zip-full-fflate.js +3 -3
- package/lib/zip-full.js +3 -3
- package/lib/zip-no-worker-deflate.js +3 -3
- package/lib/zip-no-worker-fflate-deflate.js +3 -3
- package/lib/zip-no-worker-fflate-inflate.js +3 -3
- package/lib/zip-no-worker-fflate.js +3 -3
- package/lib/zip-no-worker-inflate.js +3 -3
- package/lib/zip-no-worker.js +3 -3
- package/lib/zip.js +3 -3
- package/package.json +1 -1
- package/rollup-fflate.config.js +3 -3
- package/tests/all/test-wrapped.js +8 -4
package/lib/core/zip-writer.js
CHANGED
|
@@ -132,7 +132,7 @@ class ZipWriter {
|
|
|
132
132
|
await Promise.all(Array.from(pendingAddFileCalls));
|
|
133
133
|
}
|
|
134
134
|
await closeFile(this, comment, options);
|
|
135
|
-
if (!writer.preventClose) {
|
|
135
|
+
if (!writer.preventClose && !options.preventClose) {
|
|
136
136
|
await writable.getWriter().close();
|
|
137
137
|
}
|
|
138
138
|
return writer.getData ? writer.getData() : writable;
|
|
@@ -298,36 +298,36 @@ async function getFileEntry(zipWriter, name, reader, options) {
|
|
|
298
298
|
const previousFileEntry = Array.from(files.values()).pop();
|
|
299
299
|
let fileEntry = {};
|
|
300
300
|
let bufferedWrite;
|
|
301
|
-
let
|
|
301
|
+
let releaseLockWriter;
|
|
302
302
|
let resolveLockCurrentFileEntry;
|
|
303
|
+
let writingBufferedData;
|
|
304
|
+
let fileWriter;
|
|
303
305
|
files.set(name, fileEntry);
|
|
304
306
|
try {
|
|
305
307
|
let lockPreviousFileEntry;
|
|
306
|
-
let fileWriter;
|
|
307
308
|
if (options.keepOrder) {
|
|
308
309
|
lockPreviousFileEntry = previousFileEntry && previousFileEntry.lock;
|
|
309
310
|
}
|
|
310
311
|
fileEntry.lock = new Promise(resolve => resolveLockCurrentFileEntry = resolve);
|
|
311
|
-
if (options.bufferedWrite || zipWriter.
|
|
312
|
+
if (options.bufferedWrite || zipWriter.lockWriter || !options.dataDescriptor) {
|
|
312
313
|
fileWriter = new BlobWriter();
|
|
313
314
|
fileWriter.init();
|
|
314
315
|
bufferedWrite = true;
|
|
315
316
|
} else {
|
|
316
|
-
zipWriter.
|
|
317
|
+
zipWriter.lockWriter = Promise.resolve();
|
|
317
318
|
if (writer.init && !writer.initialized) {
|
|
318
319
|
await writer.init();
|
|
319
320
|
}
|
|
320
321
|
fileWriter = writer;
|
|
321
322
|
}
|
|
322
|
-
fileEntry = await createFileEntry(reader, fileWriter.writable, zipWriter.config, options);
|
|
323
|
+
fileEntry = await createFileEntry(reader, fileEntry, fileWriter.writable, zipWriter.config, options);
|
|
323
324
|
files.set(name, fileEntry);
|
|
324
325
|
fileEntry.filename = name;
|
|
325
326
|
if (bufferedWrite) {
|
|
326
|
-
let
|
|
327
|
-
const blob = fileWriter.getData();
|
|
327
|
+
let blob = fileWriter.getData();
|
|
328
328
|
await lockPreviousFileEntry;
|
|
329
|
-
await
|
|
330
|
-
|
|
329
|
+
await lockWriter();
|
|
330
|
+
writingBufferedData = true;
|
|
331
331
|
const { writable } = writer;
|
|
332
332
|
if (!options.dataDescriptor) {
|
|
333
333
|
const headerLength = 26;
|
|
@@ -344,10 +344,10 @@ async function getFileEntry(zipWriter, name, reader, options) {
|
|
|
344
344
|
setUint32(arrayBufferView, 22, fileEntry.uncompressedSize);
|
|
345
345
|
}
|
|
346
346
|
await writeUint8Array(writable, new Uint8Array(arrayBuffer));
|
|
347
|
-
|
|
347
|
+
blob = blob.slice(headerLength);
|
|
348
348
|
}
|
|
349
|
-
await
|
|
350
|
-
|
|
349
|
+
await blob.stream().pipeTo(writable, { preventClose: true });
|
|
350
|
+
writingBufferedData = false;
|
|
351
351
|
}
|
|
352
352
|
fileEntry.offset = zipWriter.offset;
|
|
353
353
|
if (fileEntry.zip64) {
|
|
@@ -359,32 +359,30 @@ async function getFileEntry(zipWriter, name, reader, options) {
|
|
|
359
359
|
zipWriter.offset += fileEntry.length;
|
|
360
360
|
return fileEntry;
|
|
361
361
|
} catch (error) {
|
|
362
|
-
if ((bufferedWrite &&
|
|
362
|
+
if ((bufferedWrite && writingBufferedData) || (!bufferedWrite && fileEntry.dataWritten)) {
|
|
363
363
|
error.corruptedEntry = zipWriter.hasCorruptedEntries = true;
|
|
364
|
-
|
|
365
|
-
zipWriter.offset += fileEntry.uncompressedSize;
|
|
366
|
-
}
|
|
364
|
+
zipWriter.offset += fileWriter.size;
|
|
367
365
|
}
|
|
368
366
|
files.delete(name);
|
|
369
367
|
throw error;
|
|
370
368
|
} finally {
|
|
371
369
|
resolveLockCurrentFileEntry();
|
|
372
|
-
if (
|
|
373
|
-
|
|
370
|
+
if (releaseLockWriter) {
|
|
371
|
+
releaseLockWriter();
|
|
374
372
|
}
|
|
375
373
|
}
|
|
376
374
|
|
|
377
|
-
async function
|
|
378
|
-
if (zipWriter.
|
|
379
|
-
await zipWriter.
|
|
380
|
-
await
|
|
375
|
+
async function lockWriter() {
|
|
376
|
+
if (zipWriter.lockWriter) {
|
|
377
|
+
await zipWriter.lockWriter.then(() => delete zipWriter.lockWriter);
|
|
378
|
+
await lockWriter();
|
|
381
379
|
} else {
|
|
382
|
-
zipWriter.
|
|
380
|
+
zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = resolve);
|
|
383
381
|
}
|
|
384
382
|
}
|
|
385
383
|
}
|
|
386
384
|
|
|
387
|
-
async function createFileEntry(reader, writable, config, options) {
|
|
385
|
+
async function createFileEntry(reader, pendingFileEntry, writable, config, options) {
|
|
388
386
|
const {
|
|
389
387
|
rawFilename,
|
|
390
388
|
lastAccessDate,
|
|
@@ -534,7 +532,7 @@ async function createFileEntry(reader, writable, config, options) {
|
|
|
534
532
|
let compressedSize = 0;
|
|
535
533
|
if (reader) {
|
|
536
534
|
await writeUint8Array(writable, localHeaderArray);
|
|
537
|
-
fileEntry.dataWritten = true;
|
|
535
|
+
fileEntry.dataWritten = pendingFileEntry.dataWritten = true;
|
|
538
536
|
const size = () => reader.size;
|
|
539
537
|
const readable = reader.readable;
|
|
540
538
|
readable.size = size;
|
|
@@ -562,7 +560,7 @@ async function createFileEntry(reader, writable, config, options) {
|
|
|
562
560
|
compressedSize = result.length;
|
|
563
561
|
} else {
|
|
564
562
|
await writeUint8Array(writable, localHeaderArray);
|
|
565
|
-
fileEntry.dataWritten = true;
|
|
563
|
+
fileEntry.dataWritten = pendingFileEntry.dataWritten = true;
|
|
566
564
|
}
|
|
567
565
|
let dataDescriptorArray = new Uint8Array();
|
|
568
566
|
let dataDescriptorView, dataDescriptorOffset = 0;
|
|
@@ -638,13 +636,6 @@ async function closeFile(zipWriter, comment, options) {
|
|
|
638
636
|
}
|
|
639
637
|
const directoryArray = new Uint8Array(directoryDataLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH));
|
|
640
638
|
const directoryView = getDataView(directoryArray);
|
|
641
|
-
if (comment && comment.length) {
|
|
642
|
-
if (comment.length <= MAX_16_BITS) {
|
|
643
|
-
setUint16(directoryView, offset + 20, comment.length);
|
|
644
|
-
} else {
|
|
645
|
-
throw new Error(ERR_INVALID_COMMENT);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
639
|
for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
|
|
649
640
|
const {
|
|
650
641
|
rawFilename,
|
|
@@ -728,6 +719,13 @@ async function closeFile(zipWriter, comment, options) {
|
|
|
728
719
|
setUint16(directoryView, offset + 10, filesLength);
|
|
729
720
|
setUint32(directoryView, offset + 12, directoryDataLength);
|
|
730
721
|
setUint32(directoryView, offset + 16, directoryOffset);
|
|
722
|
+
if (comment && comment.length) {
|
|
723
|
+
if (comment.length <= MAX_16_BITS) {
|
|
724
|
+
setUint16(directoryView, offset + 20, comment.length);
|
|
725
|
+
} else {
|
|
726
|
+
throw new Error(ERR_INVALID_COMMENT);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
731
729
|
const { writable } = zipWriter.writer;
|
|
732
730
|
await writeUint8Array(writable, directoryArray);
|
|
733
731
|
if (comment && comment.length) {
|
|
@@ -743,20 +741,6 @@ function sliceAsArrayBuffer(blob, start, end) {
|
|
|
743
741
|
}
|
|
744
742
|
}
|
|
745
743
|
|
|
746
|
-
async function writeBlob(writable, blob, start = 0) {
|
|
747
|
-
const blockSize = 512 * 1024 * 1024;
|
|
748
|
-
await writeSlice();
|
|
749
|
-
|
|
750
|
-
async function writeSlice() {
|
|
751
|
-
if (start < blob.size) {
|
|
752
|
-
const arrayBuffer = await sliceAsArrayBuffer(blob, start, start + blockSize);
|
|
753
|
-
await writeUint8Array(writable, new Uint8Array(arrayBuffer));
|
|
754
|
-
start += blockSize;
|
|
755
|
-
await writeSlice();
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
744
|
async function writeUint8Array(writable, array) {
|
|
761
745
|
const streamWriter = writable.getWriter();
|
|
762
746
|
await streamWriter.ready;
|
package/lib/zip-fs.js
CHANGED
|
@@ -30,9 +30,9 @@ import { configure } from "./core/configuration.js";
|
|
|
30
30
|
import configureWebWorker from "./z-worker-inline.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
32
|
import initShimAsyncCodec from "./core/util/stream-codec-shim.js";
|
|
33
|
-
import {
|
|
34
|
-
terminateWorkers,
|
|
35
|
-
ERR_ABORT
|
|
33
|
+
import {
|
|
34
|
+
terminateWorkers,
|
|
35
|
+
ERR_ABORT
|
|
36
36
|
} from "./core/codec-pool.js";
|
|
37
37
|
|
|
38
38
|
let baseURL;
|
package/lib/zip-full-fflate.js
CHANGED
|
@@ -31,9 +31,9 @@ import { configure } from "./core/configuration.js";
|
|
|
31
31
|
import configureWebWorker from "./z-worker-inline.js";
|
|
32
32
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
33
33
|
import initShimAsyncCodec from "./core/util/stream-codec-shim.js";
|
|
34
|
-
import {
|
|
35
|
-
terminateWorkers,
|
|
36
|
-
ERR_ABORT
|
|
34
|
+
import {
|
|
35
|
+
terminateWorkers,
|
|
36
|
+
ERR_ABORT
|
|
37
37
|
} from "./core/codec-pool.js";
|
|
38
38
|
|
|
39
39
|
let baseURL;
|
package/lib/zip-full.js
CHANGED
|
@@ -32,9 +32,9 @@ import { configure } from "./core/configuration.js";
|
|
|
32
32
|
import configureWebWorker from "./z-worker-inline.js";
|
|
33
33
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
34
34
|
import initShimAsyncCodec from "./core/util/stream-codec-shim.js";
|
|
35
|
-
import {
|
|
36
|
-
terminateWorkers,
|
|
37
|
-
ERR_ABORT
|
|
35
|
+
import {
|
|
36
|
+
terminateWorkers,
|
|
37
|
+
ERR_ABORT
|
|
38
38
|
} from "./core/codec-pool.js";
|
|
39
39
|
|
|
40
40
|
let baseURL;
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
import Deflate from "./core/streams/codecs/deflate.js";
|
|
30
30
|
import { configure } from "./core/configuration.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
|
-
import {
|
|
33
|
-
terminateWorkers,
|
|
34
|
-
ERR_ABORT
|
|
32
|
+
import {
|
|
33
|
+
terminateWorkers,
|
|
34
|
+
ERR_ABORT
|
|
35
35
|
} from "./core/codec-pool.js";
|
|
36
36
|
|
|
37
37
|
configure({ Deflate });
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
import { Deflate } from "./zip-fflate-shim.js";
|
|
30
30
|
import { configure } from "./core/configuration.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
|
-
import {
|
|
33
|
-
terminateWorkers,
|
|
34
|
-
ERR_ABORT
|
|
32
|
+
import {
|
|
33
|
+
terminateWorkers,
|
|
34
|
+
ERR_ABORT
|
|
35
35
|
} from "./core/codec-pool.js";
|
|
36
36
|
|
|
37
37
|
configure({ Deflate });
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
import { Inflate } from "./zip-fflate-shim.js";
|
|
30
30
|
import { configure } from "./core/configuration.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
|
-
import {
|
|
33
|
-
terminateWorkers,
|
|
34
|
-
ERR_ABORT
|
|
32
|
+
import {
|
|
33
|
+
terminateWorkers,
|
|
34
|
+
ERR_ABORT
|
|
35
35
|
} from "./core/codec-pool.js";
|
|
36
36
|
|
|
37
37
|
configure({ Inflate });
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
import { Deflate, Inflate } from "./zip-fflate-shim.js";
|
|
30
30
|
import { configure } from "./core/configuration.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
|
-
import {
|
|
33
|
-
terminateWorkers,
|
|
34
|
-
ERR_ABORT
|
|
32
|
+
import {
|
|
33
|
+
terminateWorkers,
|
|
34
|
+
ERR_ABORT
|
|
35
35
|
} from "./core/codec-pool.js";
|
|
36
36
|
|
|
37
37
|
configure({ Deflate, Inflate });
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
import Inflate from "./core/streams/codecs/inflate.js";
|
|
30
30
|
import { configure } from "./core/configuration.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
|
-
import {
|
|
33
|
-
terminateWorkers,
|
|
34
|
-
ERR_ABORT
|
|
32
|
+
import {
|
|
33
|
+
terminateWorkers,
|
|
34
|
+
ERR_ABORT
|
|
35
35
|
} from "./core/codec-pool.js";
|
|
36
36
|
|
|
37
37
|
configure({ Inflate });
|
package/lib/zip-no-worker.js
CHANGED
|
@@ -30,9 +30,9 @@ import Deflate from "./core/streams/codecs/deflate.js";
|
|
|
30
30
|
import Inflate from "./core/streams/codecs/inflate.js";
|
|
31
31
|
import { configure } from "./core/configuration.js";
|
|
32
32
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
33
|
-
import {
|
|
34
|
-
terminateWorkers,
|
|
35
|
-
ERR_ABORT
|
|
33
|
+
import {
|
|
34
|
+
terminateWorkers,
|
|
35
|
+
ERR_ABORT
|
|
36
36
|
} from "./core/codec-pool.js";
|
|
37
37
|
|
|
38
38
|
configure({ Deflate, Inflate });
|
package/lib/zip.js
CHANGED
|
@@ -30,9 +30,9 @@ import { configure } from "./core/configuration.js";
|
|
|
30
30
|
import configureWebWorker from "./z-worker-inline.js";
|
|
31
31
|
import { getMimeType } from "./core/util/default-mime-type.js";
|
|
32
32
|
import initShimAsyncCodec from "./core/util/stream-codec-shim.js";
|
|
33
|
-
import {
|
|
34
|
-
terminateWorkers,
|
|
35
|
-
ERR_ABORT
|
|
33
|
+
import {
|
|
34
|
+
terminateWorkers,
|
|
35
|
+
ERR_ABORT
|
|
36
36
|
} from "./core/codec-pool.js";
|
|
37
37
|
|
|
38
38
|
let baseURL;
|
package/package.json
CHANGED
package/rollup-fflate.config.js
CHANGED
|
@@ -3,9 +3,6 @@ import replace from "@rollup/plugin-replace";
|
|
|
3
3
|
import { terser } from "rollup-plugin-terser";
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
|
|
6
|
-
const GLOBALS = "const { Array, Object, String, BigInt, Math, Date, Map, URL, Error, Uint8Array, Uint16Array, Uint32Array, DataView, Blob, Promise, TextEncoder, TextDecoder, document, crypto, btoa, TransformStream, ReadableStream, WritableStream, CompressionStream, DecompressionStream, navigator } = globalThis;";
|
|
7
|
-
const GLOBALS_WORKER = "const { Array, Object, Math, Error, Uint8Array, Uint16Array, Uint32Array, Int32Array, DataView, Promise, TextEncoder, crypto, postMessage, TransformStream, ReadableStream, WritableStream, CompressionStream, DecompressionStream } = globalThis;";
|
|
8
|
-
|
|
9
6
|
const bundledTerserOptions = {
|
|
10
7
|
compress: {
|
|
11
8
|
unsafe: true,
|
|
@@ -33,6 +30,9 @@ const inlineTerserOptions = {
|
|
|
33
30
|
}
|
|
34
31
|
};
|
|
35
32
|
|
|
33
|
+
const GLOBALS = "const { Array, Object, String, BigInt, Math, Date, Map, URL, Error, Uint8Array, Uint16Array, Uint32Array, DataView, Blob, Promise, TextEncoder, TextDecoder, document, crypto, btoa, TransformStream, ReadableStream, WritableStream, CompressionStream, DecompressionStream, navigator } = globalThis;";
|
|
34
|
+
const GLOBALS_WORKER = "const { Array, Object, Math, Error, Uint8Array, Uint16Array, Uint32Array, Int32Array, DataView, Promise, TextEncoder, crypto, postMessage, TransformStream, ReadableStream, WritableStream, CompressionStream, DecompressionStream } = globalThis;";
|
|
35
|
+
|
|
36
36
|
export default [{
|
|
37
37
|
input: "lib/z-worker-fflate.js",
|
|
38
38
|
output: [{
|
|
@@ -5,20 +5,24 @@ import * as zip from "../../index.js";
|
|
|
5
5
|
const TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
|
|
6
6
|
const FILENAME = "lorem.txt";
|
|
7
7
|
const BLOB = new Blob([TEXT_CONTENT], { type: zip.getMimeType(FILENAME) });
|
|
8
|
+
const COMMENT = new Uint8Array([60, 61, 62]);
|
|
9
|
+
const PREPENDED_DATA = new Uint8Array([60, 61, 62]);
|
|
8
10
|
|
|
9
11
|
export { test };
|
|
10
12
|
|
|
11
13
|
async function test() {
|
|
12
14
|
zip.configure({ chunkSize: 128, useWebWorkers: true });
|
|
13
15
|
const blobWriter = new zip.BlobWriter("application/zip");
|
|
14
|
-
await blobWriter.writeUint8Array(
|
|
16
|
+
await blobWriter.writeUint8Array(PREPENDED_DATA);
|
|
15
17
|
const zipWriter = new zip.ZipWriter(blobWriter);
|
|
16
18
|
await zipWriter.add(FILENAME, new zip.BlobReader(BLOB));
|
|
17
|
-
await zipWriter.close(
|
|
18
|
-
const zipReader = new zip.ZipReader(new zip.BlobReader(blobWriter.getData()));
|
|
19
|
+
await zipWriter.close(COMMENT);
|
|
20
|
+
const zipReader = new zip.ZipReader(new zip.BlobReader(blobWriter.getData()), { extractPrependedData: true });
|
|
19
21
|
const entries = await zipReader.getEntries();
|
|
20
22
|
const data = await entries[0].getData(new zip.BlobWriter(zip.getMimeType(entries[0].filename)));
|
|
21
23
|
await zipReader.close();
|
|
24
|
+
const comment = Array.from(zipReader.comment).toString();
|
|
25
|
+
const prependedData = Array.from(zipReader.prependedData).toString();
|
|
22
26
|
zip.terminateWorkers();
|
|
23
|
-
return TEXT_CONTENT == (await data.text()) &&
|
|
27
|
+
return TEXT_CONTENT == (await data.text()) && prependedData == Array.from(PREPENDED_DATA) && comment == Array.from(COMMENT);
|
|
24
28
|
}
|