| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ef08c50 commit ca3c309
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,13 +35,13 @@ | |||
| 35 | 35 | * [HTTPS](https.md) | |
| 36 | 36 | * [Inspector](inspector.md) | |
| 37 | 37 | * [Internationalization](intl.md) | |
| 38 | + * [Iterable Streams API](stream_iter.md) | ||
| 38 | 39 | * [Modules: CommonJS modules](modules.md) | |
| 39 | 40 | * [Modules: ECMAScript modules](esm.md) | |
| 40 | 41 | * [Modules: `node:module` API](module.md) | |
| 41 | 42 | * [Modules: Packages](packages.md) | |
| 42 | 43 | * [Modules: TypeScript](typescript.md) | |
| 43 | 44 | * [Net](net.md) | |
| 44 | - * [Iterable Streams API](stream_iter.md) | ||
| 45 | 45 | * [OS](os.md) | |
| 46 | 46 | * [Path](path.md) | |
| 47 | 47 | * [Performance hooks](perf_hooks.md) | |
@@ -71,7 +71,6 @@ | |||
| 71 | 71 | * [Web Streams API](webstreams.md) | |
| 72 | 72 | * [Worker threads](worker_threads.md) | |
| 73 | 73 | * [Zlib](zlib.md) | |
| 74 | - * [Zlib Iterable Compression](zlib_iter.md) | ||
| 75 | 74 | ||
| 76 | 75 | <hr class="line"/> | |
| 77 | 76 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -416,7 +416,7 @@ if (writer.endSync() < 0) await writer.end(); | |||
| 416 | 416 | writer.fail(err); // Always synchronous, no fallback needed | |
| 417 | 417 | ``` | |
| 418 | 418 | ||
| 419 | - ### `writer.desiredSize` | ||
| 419 | + #### `writer.desiredSize` | ||
| 420 | 420 | ||
| 421 | 421 | * {number|null} | |
| 422 | 422 | ||
@@ -425,7 +425,7 @@ Returns `null` if the writer is closed or the consumer has disconnected. | |||
| 425 | 425 | ||
| 426 | 426 | The value is always non-negative. | |
| 427 | 427 | ||
| 428 | - ### `writer.end([options])` | ||
| 428 | + #### `writer.end([options])` | ||
| 429 | 429 | ||
| 430 | 430 | * `options` {Object} | |
| 431 | 431 | * `signal` {AbortSignal} Cancel just this operation. The signal cancels only | |
@@ -434,7 +434,7 @@ The value is always non-negative. | |||
| 434 | 434 | ||
| 435 | 435 | Signal that no more data will be written. | |
| 436 | 436 | ||
| 437 | - ### `writer.endSync()` | ||
| 437 | + #### `writer.endSync()` | ||
| 438 | 438 | ||
| 439 | 439 | * Returns: {number} Total bytes written, or `-1` if the writer is not open. | |
| 440 | 440 | ||
@@ -448,7 +448,7 @@ if (result < 0) { | |||
| 448 | 448 | } | |
| 449 | 449 | ``` | |
| 450 | 450 | ||
| 451 | - ### `writer.fail(reason)` | ||
| 451 | + #### `writer.fail(reason)` | ||
| 452 | 452 | ||
| 453 | 453 | * `reason` {any} | |
| 454 | 454 | ||
@@ -457,7 +457,7 @@ or errored, this is a no-op. Unlike `write()` and `end()`, `fail()` is | |||
| 457 | 457 | unconditionally synchronous because failing a writer is a pure state | |
| 458 | 458 | transition with no async work to perform. | |
| 459 | 459 | ||
| 460 | - ### `writer.write(chunk[, options])` | ||
| 460 | + #### `writer.write(chunk[, options])` | ||
| 461 | 461 | ||
| 462 | 462 | * `chunk` {Uint8Array|string} | |
| 463 | 463 | * `options` {Object} | |
@@ -467,15 +467,15 @@ transition with no async work to perform. | |||
| 467 | 467 | ||
| 468 | 468 | Write a chunk. The promise resolves when buffer space is available. | |
| 469 | 469 | ||
| 470 | - ### `writer.writeSync(chunk)` | ||
| 470 | + #### `writer.writeSync(chunk)` | ||
| 471 | 471 | ||
| 472 | 472 | * `chunk` {Uint8Array|string} | |
| 473 | 473 | * Returns: {boolean} `true` if the write was accepted, `false` if the | |
| 474 | 474 | buffer is full. | |
| 475 | 475 | ||
| 476 | 476 | Synchronous write. Does not block; returns `false` if backpressure is active. | |
| 477 | 477 | ||
| 478 | - ### `writer.writev(chunks[, options])` | ||
| 478 | + #### `writer.writev(chunks[, options])` | ||
| 479 | 479 | ||
| 480 | 480 | * `chunks` {Uint8Array\[]|string\[]} | |
| 481 | 481 | * `options` {Object} | |
@@ -485,7 +485,7 @@ Synchronous write. Does not block; returns `false` if backpressure is active. | |||
| 485 | 485 | ||
| 486 | 486 | Write multiple chunks as a single batch. | |
| 487 | 487 | ||
| 488 | - ### `writer.writevSync(chunks)` | ||
| 488 | + #### `writer.writevSync(chunks)` | ||
| 489 | 489 | ||
| 490 | 490 | * `chunks` {Uint8Array\[]|string\[]} | |
| 491 | 491 | * Returns: {boolean} `true` if the write was accepted, `false` if the | |
@@ -1422,7 +1422,7 @@ added: v26.0.0 | |||
| 1422 | 1422 | ||
| 1423 | 1423 | Compression and decompression transforms for use with `pull()`, `pullSync()`, | |
| 1424 | 1424 | `pipeTo()`, and `pipeToSync()` are available via the [`node:zlib/iter`][] | |
| 1425 | - module. See the [`node:zlib/iter` documentation][] for details. | ||
| 1425 | + module. See the [`node:zlib/iter` documentation][`node:zlib/iter`] for details. | ||
| 1426 | 1426 | ||
| 1427 | 1427 | ## Classic stream interop | |
| 1428 | 1428 | ||
@@ -2069,8 +2069,7 @@ console.log(textSync(stream)); // 'hello world' | |||
| 2069 | 2069 | [`bytes()`]: #bytessource-options | |
| 2070 | 2070 | [`from()`]: #frominput | |
| 2071 | 2071 | [`fromSync()`]: #fromsyncinput | |
| 2072 | - [`node:zlib/iter`]: zlib_iter.md | ||
| 2073 | - [`node:zlib/iter` documentation]: zlib_iter.md | ||
| 2072 | + [`node:zlib/iter`]: zlib.md#iterable-compression | ||
| 2074 | 2073 | [`pipeTo()`]: #pipetosource-transforms-writer-options | |
| 2075 | 2074 | [`pull()`]: #pullsource-transforms-options | |
| 2076 | 2075 | [`pullSync()`]: #pullsyncsource-transforms-options | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1746,11 +1746,261 @@ added: | |||
| 1746 | 1746 | ||
| 1747 | 1747 | Decompress a chunk of data with [`ZstdDecompress`][]. | |
| 1748 | 1748 | ||
| 1749 | + ## Iterable Compression | ||
| 1750 | + | ||
| 1751 | + <!-- YAML | ||
| 1752 | + added: v25.9.0 | ||
| 1753 | + --> | ||
| 1754 | + | ||
| 1755 | + > Stability: 1 - Experimental | ||
| 1756 | + | ||
| 1757 | + The `node:zlib/iter` module provides compression and decompression transforms | ||
| 1758 | + for use with the [`node:stream/iter`][] iterable streams API. | ||
| 1759 | + | ||
| 1760 | + This module is available only when the `--experimental-stream-iter` CLI flag | ||
| 1761 | + is enabled. | ||
| 1762 | + | ||
| 1763 | + Each algorithm has both an async variant (stateful async generator, for use | ||
| 1764 | + with [`pull()`][] and [`pipeTo()`][]) and a sync variant (stateful sync | ||
| 1765 | + generator, for use with `pullSync()` and `pipeToSync()`). | ||
| 1766 | + | ||
| 1767 | + The async transforms run compression on the libuv threadpool, overlapping | ||
| 1768 | + I/O with JavaScript execution. The sync transforms run compression directly | ||
| 1769 | + on the main thread. | ||
| 1770 | + | ||
| 1771 | + > Note: The defaults for these transforms are tuned for streaming throughput, | ||
| 1772 | + > and differ from the defaults in `node:zlib`. In particular, gzip/deflate | ||
| 1773 | + > default to level 4 (not 6) and memLevel 9 (not 8), and Brotli defaults to | ||
| 1774 | + > quality 6 (not 11). These choices match common HTTP server configurations | ||
| 1775 | + > and provide significantly faster compression with only a small reduction in | ||
| 1776 | + > compression ratio. All defaults can be overridden via options. | ||
| 1777 | + | ||
| 1778 | + ```mjs | ||
| 1779 | + import { from, pull, bytes, text } from 'node:stream/iter'; | ||
| 1780 | + import { compressGzip, decompressGzip } from 'node:zlib/iter'; | ||
| 1781 | + | ||
| 1782 | + // Async round-trip | ||
| 1783 | + const compressed = await bytes(pull(from('hello'), compressGzip())); | ||
| 1784 | + const original = await text(pull(from(compressed), decompressGzip())); | ||
| 1785 | + console.log(original); // 'hello' | ||
| 1786 | + ``` | ||
| 1787 | + | ||
| 1788 | + ```cjs | ||
| 1789 | + const { from, pull, bytes, text } = require('node:stream/iter'); | ||
| 1790 | + const { compressGzip, decompressGzip } = require('node:zlib/iter'); | ||
| 1791 | + | ||
| 1792 | + async function run() { | ||
| 1793 | + const compressed = await bytes(pull(from('hello'), compressGzip())); | ||
| 1794 | + const original = await text(pull(from(compressed), decompressGzip())); | ||
| 1795 | + console.log(original); // 'hello' | ||
| 1796 | + } | ||
| 1797 | + | ||
| 1798 | + run().catch(console.error); | ||
| 1799 | + ``` | ||
| 1800 | + | ||
| 1801 | + ```mjs | ||
| 1802 | + import { fromSync, pullSync, textSync } from 'node:stream/iter'; | ||
| 1803 | + import { compressGzipSync, decompressGzipSync } from 'node:zlib/iter'; | ||
| 1804 | + | ||
| 1805 | + // Sync round-trip | ||
| 1806 | + const compressed = pullSync(fromSync('hello'), compressGzipSync()); | ||
| 1807 | + const original = textSync(pullSync(compressed, decompressGzipSync())); | ||
| 1808 | + console.log(original); // 'hello' | ||
| 1809 | + ``` | ||
| 1810 | + | ||
| 1811 | + ```cjs | ||
| 1812 | + const { fromSync, pullSync, textSync } = require('node:stream/iter'); | ||
| 1813 | + const { compressGzipSync, decompressGzipSync } = require('node:zlib/iter'); | ||
| 1814 | + | ||
| 1815 | + const compressed = pullSync(fromSync('hello'), compressGzipSync()); | ||
| 1816 | + const original = textSync(pullSync(compressed, decompressGzipSync())); | ||
| 1817 | + console.log(original); // 'hello' | ||
| 1818 | + ``` | ||
| 1819 | + | ||
| 1820 | + ### `compressBrotli([options])` | ||
| 1821 | + | ||
| 1822 | + ### `compressBrotliSync([options])` | ||
| 1823 | + | ||
| 1824 | + <!-- YAML | ||
| 1825 | + added: v25.9.0 | ||
| 1826 | + --> | ||
| 1827 | + | ||
| 1828 | + * `options` {Object} | ||
| 1829 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1830 | + * `params` {Object} Key-value object where keys and values are | ||
| 1831 | + `zlib.constants` entries. The most important compressor parameters are: | ||
| 1832 | + * `BROTLI_PARAM_MODE` -- `BROTLI_MODE_GENERIC` (default), | ||
| 1833 | + `BROTLI_MODE_TEXT`, or `BROTLI_MODE_FONT`. | ||
| 1834 | + * `BROTLI_PARAM_QUALITY` -- ranges from `BROTLI_MIN_QUALITY` to | ||
| 1835 | + `BROTLI_MAX_QUALITY`. **Default:** `6` (not `BROTLI_DEFAULT_QUALITY` | ||
| 1836 | + which is 11). Quality 6 is appropriate for streaming; quality 11 is | ||
| 1837 | + intended for offline/build-time compression. | ||
| 1838 | + * `BROTLI_PARAM_SIZE_HINT` -- expected input size. **Default:** `0` | ||
| 1839 | + (unknown). | ||
| 1840 | + * `BROTLI_PARAM_LGWIN` -- window size (log2). **Default:** `20` (1 MB). | ||
| 1841 | + The Brotli library default is 22 (4 MB); the reduced default saves | ||
| 1842 | + memory without significant compression impact for streaming workloads. | ||
| 1843 | + * `BROTLI_PARAM_LGBLOCK` -- input block size (log2). | ||
| 1844 | + See the [Brotli compressor options][] in the zlib documentation for the | ||
| 1845 | + full list. | ||
| 1846 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1847 | + * Returns: {Object} A stateful transform. | ||
| 1848 | + | ||
| 1849 | + Create a Brotli compression transform. Output is compatible with | ||
| 1850 | + `zlib.brotliDecompress()` and `decompressBrotli()`/`decompressBrotliSync()`. | ||
| 1851 | + | ||
| 1852 | + ### `compressDeflate([options])` | ||
| 1853 | + | ||
| 1854 | + ### `compressDeflateSync([options])` | ||
| 1855 | + | ||
| 1856 | + <!-- YAML | ||
| 1857 | + added: v25.9.0 | ||
| 1858 | + --> | ||
| 1859 | + | ||
| 1860 | + * `options` {Object} | ||
| 1861 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1862 | + * `level` {number} Compression level (`0`-`9`). **Default:** `4`. | ||
| 1863 | + * `windowBits` {number} **Default:** `Z_DEFAULT_WINDOWBITS` (15). | ||
| 1864 | + * `memLevel` {number} **Default:** `9`. | ||
| 1865 | + * `strategy` {number} **Default:** `Z_DEFAULT_STRATEGY`. | ||
| 1866 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1867 | + * Returns: {Object} A stateful transform. | ||
| 1868 | + | ||
| 1869 | + Create a deflate compression transform. Output is compatible with | ||
| 1870 | + `zlib.inflate()` and `decompressDeflate()`/`decompressDeflateSync()`. | ||
| 1871 | + | ||
| 1872 | + ### `compressGzip([options])` | ||
| 1873 | + | ||
| 1874 | + ### `compressGzipSync([options])` | ||
| 1875 | + | ||
| 1876 | + <!-- YAML | ||
| 1877 | + added: v25.9.0 | ||
| 1878 | + --> | ||
| 1879 | + | ||
| 1880 | + * `options` {Object} | ||
| 1881 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1882 | + * `level` {number} Compression level (`0`-`9`). **Default:** `4`. | ||
| 1883 | + * `windowBits` {number} **Default:** `Z_DEFAULT_WINDOWBITS` (15). | ||
| 1884 | + * `memLevel` {number} **Default:** `9`. | ||
| 1885 | + * `strategy` {number} **Default:** `Z_DEFAULT_STRATEGY`. | ||
| 1886 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1887 | + * Returns: {Object} A stateful transform. | ||
| 1888 | + | ||
| 1889 | + Create a gzip compression transform. Output is compatible with `zlib.gunzip()` | ||
| 1890 | + and `decompressGzip()`/`decompressGzipSync()`. | ||
| 1891 | + | ||
| 1892 | + ### `compressZstd([options])` | ||
| 1893 | + | ||
| 1894 | + ### `compressZstdSync([options])` | ||
| 1895 | + | ||
| 1896 | + <!-- YAML | ||
| 1897 | + added: v25.9.0 | ||
| 1898 | + --> | ||
| 1899 | + | ||
| 1900 | + * `options` {Object} | ||
| 1901 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1902 | + * `params` {Object} Key-value object where keys and values are | ||
| 1903 | + `zlib.constants` entries. The most important compressor parameters are: | ||
| 1904 | + * `ZSTD_c_compressionLevel` -- **Default:** `ZSTD_CLEVEL_DEFAULT` (3). | ||
| 1905 | + * `ZSTD_c_checksumFlag` -- generate a checksum. **Default:** `0`. | ||
| 1906 | + * `ZSTD_c_strategy` -- compression strategy. Values include | ||
| 1907 | + `ZSTD_fast`, `ZSTD_dfast`, `ZSTD_greedy`, `ZSTD_lazy`, | ||
| 1908 | + `ZSTD_lazy2`, `ZSTD_btlazy2`, `ZSTD_btopt`, `ZSTD_btultra`, | ||
| 1909 | + `ZSTD_btultra2`. | ||
| 1910 | + See the [Zstd compressor options][] in the zlib documentation for the | ||
| 1911 | + full list. | ||
| 1912 | + * `pledgedSrcSize` {number} Expected uncompressed size (optional hint). | ||
| 1913 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1914 | + * Returns: {Object} A stateful transform. | ||
| 1915 | + | ||
| 1916 | + Create a Zstandard compression transform. Output is compatible with | ||
| 1917 | + `zlib.zstdDecompress()` and `decompressZstd()`/`decompressZstdSync()`. | ||
| 1918 | + | ||
| 1919 | + ### `decompressBrotli([options])` | ||
| 1920 | + | ||
| 1921 | + ### `decompressBrotliSync([options])` | ||
| 1922 | + | ||
| 1923 | + <!-- YAML | ||
| 1924 | + added: v25.9.0 | ||
| 1925 | + --> | ||
| 1926 | + | ||
| 1927 | + * `options` {Object} | ||
| 1928 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1929 | + * `params` {Object} Key-value object where keys and values are | ||
| 1930 | + `zlib.constants` entries. Available decompressor parameters: | ||
| 1931 | + * `BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION` -- boolean | ||
| 1932 | + flag affecting internal memory allocation. | ||
| 1933 | + * `BROTLI_DECODER_PARAM_LARGE_WINDOW` -- boolean flag enabling "Large | ||
| 1934 | + Window Brotli" mode (not compatible with [RFC 7932][]). | ||
| 1935 | + See the [Brotli decompressor options][] in the zlib documentation for | ||
| 1936 | + details. | ||
| 1937 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1938 | + * Returns: {Object} A stateful transform. | ||
| 1939 | + | ||
| 1940 | + Create a Brotli decompression transform. | ||
| 1941 | + | ||
| 1942 | + ### `decompressDeflate([options])` | ||
| 1943 | + | ||
| 1944 | + ### `decompressDeflateSync([options])` | ||
| 1945 | + | ||
| 1946 | + <!-- YAML | ||
| 1947 | + added: v25.9.0 | ||
| 1948 | + --> | ||
| 1949 | + | ||
| 1950 | + * `options` {Object} | ||
| 1951 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1952 | + * `windowBits` {number} **Default:** `Z_DEFAULT_WINDOWBITS` (15). | ||
| 1953 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1954 | + * Returns: {Object} A stateful transform. | ||
| 1955 | + | ||
| 1956 | + Create a deflate decompression transform. | ||
| 1957 | + | ||
| 1958 | + ### `decompressGzip([options])` | ||
| 1959 | + | ||
| 1960 | + ### `decompressGzipSync([options])` | ||
| 1961 | + | ||
| 1962 | + <!-- YAML | ||
| 1963 | + added: v25.9.0 | ||
| 1964 | + --> | ||
| 1965 | + | ||
| 1966 | + * `options` {Object} | ||
| 1967 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1968 | + * `windowBits` {number} **Default:** `Z_DEFAULT_WINDOWBITS` (15). | ||
| 1969 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1970 | + * Returns: {Object} A stateful transform. | ||
| 1971 | + | ||
| 1972 | + Create a gzip decompression transform. | ||
| 1973 | + | ||
| 1974 | + ### `decompressZstd([options])` | ||
| 1975 | + | ||
| 1976 | + ### `decompressZstdSync([options])` | ||
| 1977 | + | ||
| 1978 | + <!-- YAML | ||
| 1979 | + added: v25.9.0 | ||
| 1980 | + --> | ||
| 1981 | + | ||
| 1982 | + * `options` {Object} | ||
| 1983 | + * `chunkSize` {number} Output buffer size. **Default:** `65536` (64 KB). | ||
| 1984 | + * `params` {Object} Key-value object where keys and values are | ||
| 1985 | + `zlib.constants` entries. Available decompressor parameters: | ||
| 1986 | + * `ZSTD_d_windowLogMax` -- maximum window size (log2) the decompressor | ||
| 1987 | + will allocate. Limits memory usage against malicious input. | ||
| 1988 | + See the [Zstd decompressor options][] in the zlib documentation for | ||
| 1989 | + details. | ||
| 1990 | + * `dictionary` {Buffer|TypedArray|DataView} | ||
| 1991 | + * Returns: {Object} A stateful transform. | ||
| 1992 | + | ||
| 1993 | + Create a Zstandard decompression transform. | ||
| 1994 | + | ||
| 1995 | + [Brotli compressor options]: #compressor-options | ||
| 1996 | + [Brotli decompressor options]: #decompressor-options | ||
| 1749 | 1997 | [Brotli parameters]: #brotli-constants | |
| 1750 | 1998 | [Cyclic redundancy check]: https://en.wikipedia.org/wiki/Cyclic_redundancy_check | |
| 1751 | 1999 | [Memory usage tuning]: #memory-usage-tuning | |
| 1752 | - [RFC 7932]: https://www.rfc-editor.org/rfc/rfc7932.txt | ||
| 2000 | + [RFC 7932]: https://www.rfc-editor.org/rfc/rfc7932.html | ||
| 1753 | 2001 | [Streams API]: stream.md | |
| 2002 | + [Zstd compressor options]: #compressor-options-1 | ||
| 2003 | + [Zstd decompressor options]: #decompressor-options-1 | ||
| 1754 | 2004 | [Zstd parameters]: #zstd-constants | |
| 1755 | 2005 | [`.flush()`]: #zlibflushkind-callback | |
| 1756 | 2006 | [`Accept-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 | |
@@ -1769,6 +2019,9 @@ Decompress a chunk of data with [`ZstdDecompress`][]. | |||
| 1769 | 2019 | [`ZstdDecompress`]: #class-zlibzstddecompress | |
| 1770 | 2020 | [`buffer.kMaxLength`]: buffer.md#bufferkmaxlength | |
| 1771 | 2021 | [`deflateInit2` and `inflateInit2`]: https://zlib.net/manual.html#Advanced | |
| 2022 | + [`node:stream/iter`]: stream_iter.md | ||
| 2023 | + [`pipeTo()`]: stream_iter.md#pipetosource-transforms-writer-options | ||
| 2024 | + [`pull()`]: stream_iter.md#pullsource-transforms-options | ||
| 1772 | 2025 | [`stream.Transform`]: stream.md#class-streamtransform | |
| 1773 | 2026 | [convenience methods]: #convenience-methods | |
| 1774 | 2027 | [zlib documentation]: https://zlib.net/manual.html#Constants | |
| Back | FazBrowse Home | New Git URL |
0 commit comments