From cc0d5a8b9bd14ff8eba57da44b45a924c636744d Mon Sep 17 00:00:00 2001 From: "Michael B." Date: Thu, 7 Dec 2023 13:02:55 +0100 Subject: [PATCH] leveldb: update docs --- README.md | 4 +- doc/formats.md | 299 ++++++++++-------- .../testdata/leveldb_manifest_torepr.fqtest | 39 +++ 3 files changed, 207 insertions(+), 135 deletions(-) create mode 100644 format/leveldb/testdata/leveldb_manifest_torepr.fqtest diff --git a/README.md b/README.md index 8325300f..01c57bce 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,9 @@ ipv6_packet, jpeg, json, jsonl, -[leveldb_ldb](doc/formats.md#leveldb_ldb), +[leveldb_descriptor](doc/formats.md#leveldb_descriptor), +[leveldb_log](doc/formats.md#leveldb_log), +[leveldb_table](doc/formats.md#leveldb_table), [luajit](doc/formats.md#luajit), [macho](doc/formats.md#macho), macho_fat, diff --git a/doc/formats.md b/doc/formats.md index 311fb6ce..f85fead9 100644 --- a/doc/formats.md +++ b/doc/formats.md @@ -2,139 +2,141 @@ [fq -rn -L . 'include "formats"; formats_table']: sh-start -|Name |Description |Dependencies| -|- |- |-| -|[`aac_frame`](#aac_frame) |Advanced Audio Coding frame || -|`adts` |Audio Data Transport Stream |`adts_frame`| -|`adts_frame` |Audio Data Transport Stream frame |`aac_frame`| -|`aiff` |Audio Interchange File Format || -|`amf0` |Action Message Format 0 || -|`apev2` |APEv2 metadata tag |`image`| -|[`apple_bookmark`](#apple_bookmark) |Apple BookmarkData || -|`ar` |Unix archive |`probe`| -|[`asn1_ber`](#asn1_ber) |ASN1 BER (basic encoding rules, also CER and DER) || -|`av1_ccr` |AV1 Codec Configuration Record || -|`av1_frame` |AV1 frame |`av1_obu`| -|`av1_obu` |AV1 Open Bitstream Unit || -|`avc_annexb` |H.264/AVC Annex B |`avc_nalu`| -|[`avc_au`](#avc_au) |H.264/AVC Access Unit |`avc_nalu`| -|`avc_dcr` |H.264/AVC Decoder Configuration Record |`avc_nalu`| -|`avc_nalu` |H.264/AVC Network Access Layer Unit |`avc_sps` `avc_pps` `avc_sei`| -|`avc_pps` |H.264/AVC Picture Parameter Set || -|`avc_sei` |H.264/AVC Supplemental Enhancement Information || -|`avc_sps` |H.264/AVC Sequence Parameter Set || -|[`avi`](#avi) |Audio Video Interleaved |`avc_au` `hevc_au` `mp3_frame` `flac_frame`| -|[`avro_ocf`](#avro_ocf) |Avro object container file || -|[`bencode`](#bencode) |BitTorrent bencoding || -|`bitcoin_blkdat` |Bitcoin blk.dat |`bitcoin_block`| -|[`bitcoin_block`](#bitcoin_block) |Bitcoin block |`bitcoin_transaction`| -|`bitcoin_script` |Bitcoin script || -|`bitcoin_transaction` |Bitcoin transaction |`bitcoin_script`| -|[`bits`](#bits) |Raw bits || -|[`bplist`](#bplist) |Apple Binary Property List || -|`bsd_loopback_frame` |BSD loopback frame |`inet_packet`| -|[`bson`](#bson) |Binary JSON || -|[`bytes`](#bytes) |Raw bytes || -|`bzip2` |bzip2 compression |`probe`| -|[`caff`](#caff) |Live2D Cubism archive |`probe`| -|[`cbor`](#cbor) |Concise Binary Object Representation || -|[`csv`](#csv) |Comma separated values || -|`dns` |DNS packet || -|`dns_tcp` |DNS packet (TCP) || -|`elf` |Executable and Linkable Format || -|`ether8023_frame` |Ethernet 802.3 frame |`inet_packet`| -|`exif` |Exchangeable Image File Format || -|`fairplay_spc` |FairPlay Server Playback Context || -|`flac` |Free Lossless Audio Codec file |`flac_metadatablocks` `flac_frame`| -|[`flac_frame`](#flac_frame) |FLAC frame || -|`flac_metadatablock` |FLAC metadatablock |`flac_streaminfo` `flac_picture` `vorbis_comment`| -|`flac_metadatablocks` |FLAC metadatablocks |`flac_metadatablock`| -|`flac_picture` |FLAC metadatablock picture |`image`| -|`flac_streaminfo` |FLAC streaminfo || -|`gif` |Graphics Interchange Format || -|`gzip` |gzip compression |`probe`| -|`hevc_annexb` |H.265/HEVC Annex B |`hevc_nalu`| -|[`hevc_au`](#hevc_au) |H.265/HEVC Access Unit |`hevc_nalu`| -|`hevc_dcr` |H.265/HEVC Decoder Configuration Record |`hevc_nalu`| -|`hevc_nalu` |H.265/HEVC Network Access Layer Unit |`hevc_vps` `hevc_pps` `hevc_sps`| -|`hevc_pps` |H.265/HEVC Picture Parameter Set || -|`hevc_sps` |H.265/HEVC Sequence Parameter Set || -|`hevc_vps` |H.265/HEVC Video Parameter Set || -|[`html`](#html) |HyperText Markup Language || -|`icc_profile` |International Color Consortium profile || -|`icmp` |Internet Control Message Protocol || -|`icmpv6` |Internet Control Message Protocol v6 || -|`id3v1` |ID3v1 metadata || -|`id3v11` |ID3v1.1 metadata || -|`id3v2` |ID3v2 metadata |`image`| -|`ipv4_packet` |Internet protocol v4 packet |`ip_packet`| -|`ipv6_packet` |Internet protocol v6 packet |`ip_packet`| -|`jpeg` |Joint Photographic Experts Group file |`exif` `icc_profile`| -|`json` |JavaScript Object Notation || -|`jsonl` |JavaScript Object Notation Lines || -|[`leveldb_ldb`](#leveldb_ldb) |LevelDB Table || -|[`luajit`](#luajit) |LuaJIT 2.0 bytecode || -|[`macho`](#macho) |Mach-O macOS executable || -|`macho_fat` |Fat Mach-O macOS executable (multi-architecture) |`macho`| -|[`markdown`](#markdown) |Markdown || -|[`matroska`](#matroska) |Matroska file |`aac_frame` `av1_ccr` `av1_frame` `avc_au` `avc_dcr` `flac_frame` `flac_metadatablocks` `hevc_au` `hevc_dcr` `image` `mp3_frame` `mpeg_asc` `mpeg_pes_packet` `mpeg_spu` `opus_packet` `vorbis_packet` `vp8_frame` `vp9_cfm` `vp9_frame`| -|[`moc3`](#moc3) |MOC3 file || -|[`mp3`](#mp3) |MP3 file |`id3v2` `id3v1` `id3v11` `apev2` `mp3_frame`| -|`mp3_frame` |MPEG audio layer 3 frame |`mp3_frame_tags`| -|`mp3_frame_vbri` |MP3 frame Fraunhofer encoder variable bitrate tag || -|`mp3_frame_xing` |MP3 frame Xing/Info tag || -|[`mp4`](#mp4) |ISOBMFF, QuickTime and similar |`aac_frame` `av1_ccr` `av1_frame` `avc_au` `avc_dcr` `flac_frame` `flac_metadatablocks` `hevc_au` `hevc_dcr` `icc_profile` `id3v2` `image` `jpeg` `mp3_frame` `mpeg_es` `mpeg_pes_packet` `opus_packet` `png` `prores_frame` `protobuf_widevine` `pssh_playready` `vorbis_packet` `vp9_frame` `vpx_ccr`| -|`mpeg_asc` |MPEG-4 Audio Specific Config || -|`mpeg_es` |MPEG Elementary Stream |`mpeg_asc` `vorbis_packet`| -|`mpeg_pes` |MPEG Packetized elementary stream |`mpeg_pes_packet` `mpeg_spu`| -|`mpeg_pes_packet` |MPEG Packetized elementary stream packet || -|`mpeg_spu` |Sub Picture Unit (DVD subtitle) || -|`mpeg_ts` |MPEG Transport Stream || -|[`msgpack`](#msgpack) |MessagePack || -|`ogg` |OGG file |`ogg_page` `vorbis_packet` `opus_packet` `flac_metadatablock` `flac_frame`| -|`ogg_page` |OGG page || -|[`opentimestamps`](#opentimestamps) |OpenTimestamps file || -|`opus_packet` |Opus packet |`vorbis_comment`| -|[`pcap`](#pcap) |PCAP packet capture |`link_frame` `tcp_stream` `ipv4_packet`| -|`pcapng` |PCAPNG packet capture |`link_frame` `tcp_stream` `ipv4_packet`| -|[`pg_btree`](#pg_btree) |PostgreSQL btree index file || -|[`pg_control`](#pg_control) |PostgreSQL control file || -|[`pg_heap`](#pg_heap) |PostgreSQL heap file || -|`png` |Portable Network Graphics file |`icc_profile` `exif`| -|`prores_frame` |Apple ProRes frame || -|[`protobuf`](#protobuf) |Protobuf || -|`protobuf_widevine` |Widevine protobuf |`protobuf`| -|`pssh_playready` |PlayReady PSSH || -|[`rtmp`](#rtmp) |Real-Time Messaging Protocol |`amf0` `mpeg_asc`| -|`sll2_packet` |Linux cooked capture encapsulation v2 |`inet_packet`| -|`sll_packet` |Linux cooked capture encapsulation |`inet_packet`| -|`tar` |Tar archive |`probe`| -|`tcp_segment` |Transmission control protocol segment || -|`tiff` |Tag Image File Format |`icc_profile`| -|[`tls`](#tls) |Transport layer security |`asn1_ber`| -|`toml` |Tom's Obvious, Minimal Language || -|[`tzif`](#tzif) |Time Zone Information Format || -|`udp_datagram` |User datagram protocol |`udp_payload`| -|`vorbis_comment` |Vorbis comment |`flac_picture`| -|`vorbis_packet` |Vorbis packet |`vorbis_comment`| -|`vp8_frame` |VP8 frame || -|`vp9_cfm` |VP9 Codec Feature Metadata || -|`vp9_frame` |VP9 frame || -|`vpx_ccr` |VPX Codec Configuration Record || -|[`wasm`](#wasm) |WebAssembly Binary Format || -|`wav` |WAV file |`id3v2` `id3v1` `id3v11`| -|`webp` |WebP image |`exif` `vp8_frame` `icc_profile` `xml`| -|[`xml`](#xml) |Extensible Markup Language || -|`yaml` |YAML Ain't Markup Language || -|[`zip`](#zip) |ZIP archive |`probe`| -|`image` |Group |`gif` `jpeg` `mp4` `png` `tiff` `webp`| -|`inet_packet` |Group |`ipv4_packet` `ipv6_packet`| -|`ip_packet` |Group |`icmp` `icmpv6` `tcp_segment` `udp_datagram`| -|`link_frame` |Group |`bsd_loopback_frame` `ether8023_frame` `ipv4_packet` `ipv6_packet` `sll2_packet` `sll_packet`| -|`mp3_frame_tags` |Group |`mp3_frame_vbri` `mp3_frame_xing`| -|`probe` |Group |`adts` `aiff` `apple_bookmark` `ar` `avi` `avro_ocf` `bitcoin_blkdat` `bplist` `bzip2` `caff` `elf` `flac` `gif` `gzip` `html` `jpeg` `json` `jsonl` `leveldb_ldb` `luajit` `macho` `macho_fat` `matroska` `moc3` `mp3` `mp4` `mpeg_ts` `ogg` `opentimestamps` `pcap` `pcapng` `png` `tar` `tiff` `toml` `tzif` `wasm` `wav` `webp` `xml` `yaml` `zip`| -|`tcp_stream` |Group |`dns_tcp` `rtmp` `tls`| -|`udp_payload` |Group |`dns`| +|Name |Description |Dependencies| +|- |- |-| +|[`aac_frame`](#aac_frame) |Advanced Audio Coding frame || +|`adts` |Audio Data Transport Stream |`adts_frame`| +|`adts_frame` |Audio Data Transport Stream frame |`aac_frame`| +|`aiff` |Audio Interchange File Format || +|`amf0` |Action Message Format 0 || +|`apev2` |APEv2 metadata tag |`image`| +|[`apple_bookmark`](#apple_bookmark) |Apple BookmarkData || +|`ar` |Unix archive |`probe`| +|[`asn1_ber`](#asn1_ber) |ASN1 BER (basic encoding rules, also CER and DER) || +|`av1_ccr` |AV1 Codec Configuration Record || +|`av1_frame` |AV1 frame |`av1_obu`| +|`av1_obu` |AV1 Open Bitstream Unit || +|`avc_annexb` |H.264/AVC Annex B |`avc_nalu`| +|[`avc_au`](#avc_au) |H.264/AVC Access Unit |`avc_nalu`| +|`avc_dcr` |H.264/AVC Decoder Configuration Record |`avc_nalu`| +|`avc_nalu` |H.264/AVC Network Access Layer Unit |`avc_sps` `avc_pps` `avc_sei`| +|`avc_pps` |H.264/AVC Picture Parameter Set || +|`avc_sei` |H.264/AVC Supplemental Enhancement Information || +|`avc_sps` |H.264/AVC Sequence Parameter Set || +|[`avi`](#avi) |Audio Video Interleaved |`avc_au` `hevc_au` `mp3_frame` `flac_frame`| +|[`avro_ocf`](#avro_ocf) |Avro object container file || +|[`bencode`](#bencode) |BitTorrent bencoding || +|`bitcoin_blkdat` |Bitcoin blk.dat |`bitcoin_block`| +|[`bitcoin_block`](#bitcoin_block) |Bitcoin block |`bitcoin_transaction`| +|`bitcoin_script` |Bitcoin script || +|`bitcoin_transaction` |Bitcoin transaction |`bitcoin_script`| +|[`bits`](#bits) |Raw bits || +|[`bplist`](#bplist) |Apple Binary Property List || +|`bsd_loopback_frame` |BSD loopback frame |`inet_packet`| +|[`bson`](#bson) |Binary JSON || +|[`bytes`](#bytes) |Raw bytes || +|`bzip2` |bzip2 compression |`probe`| +|[`caff`](#caff) |Live2D Cubism archive |`probe`| +|[`cbor`](#cbor) |Concise Binary Object Representation || +|[`csv`](#csv) |Comma separated values || +|`dns` |DNS packet || +|`dns_tcp` |DNS packet (TCP) || +|`elf` |Executable and Linkable Format || +|`ether8023_frame` |Ethernet 802.3 frame |`inet_packet`| +|`exif` |Exchangeable Image File Format || +|`fairplay_spc` |FairPlay Server Playback Context || +|`flac` |Free Lossless Audio Codec file |`flac_metadatablocks` `flac_frame`| +|[`flac_frame`](#flac_frame) |FLAC frame || +|`flac_metadatablock` |FLAC metadatablock |`flac_streaminfo` `flac_picture` `vorbis_comment`| +|`flac_metadatablocks` |FLAC metadatablocks |`flac_metadatablock`| +|`flac_picture` |FLAC metadatablock picture |`image`| +|`flac_streaminfo` |FLAC streaminfo || +|`gif` |Graphics Interchange Format || +|`gzip` |gzip compression |`probe`| +|`hevc_annexb` |H.265/HEVC Annex B |`hevc_nalu`| +|[`hevc_au`](#hevc_au) |H.265/HEVC Access Unit |`hevc_nalu`| +|`hevc_dcr` |H.265/HEVC Decoder Configuration Record |`hevc_nalu`| +|`hevc_nalu` |H.265/HEVC Network Access Layer Unit |`hevc_vps` `hevc_pps` `hevc_sps`| +|`hevc_pps` |H.265/HEVC Picture Parameter Set || +|`hevc_sps` |H.265/HEVC Sequence Parameter Set || +|`hevc_vps` |H.265/HEVC Video Parameter Set || +|[`html`](#html) |HyperText Markup Language || +|`icc_profile` |International Color Consortium profile || +|`icmp` |Internet Control Message Protocol || +|`icmpv6` |Internet Control Message Protocol v6 || +|`id3v1` |ID3v1 metadata || +|`id3v11` |ID3v1.1 metadata || +|`id3v2` |ID3v2 metadata |`image`| +|`ipv4_packet` |Internet protocol v4 packet |`ip_packet`| +|`ipv6_packet` |Internet protocol v6 packet |`ip_packet`| +|`jpeg` |Joint Photographic Experts Group file |`exif` `icc_profile`| +|`json` |JavaScript Object Notation || +|`jsonl` |JavaScript Object Notation Lines || +|[`leveldb_descriptor`](#leveldb_descriptor) |LevelDB Descriptor || +|[`leveldb_log`](#leveldb_log) |LevelDB Log || +|[`leveldb_table`](#leveldb_table) |LevelDB Table || +|[`luajit`](#luajit) |LuaJIT 2.0 bytecode || +|[`macho`](#macho) |Mach-O macOS executable || +|`macho_fat` |Fat Mach-O macOS executable (multi-architecture) |`macho`| +|[`markdown`](#markdown) |Markdown || +|[`matroska`](#matroska) |Matroska file |`aac_frame` `av1_ccr` `av1_frame` `avc_au` `avc_dcr` `flac_frame` `flac_metadatablocks` `hevc_au` `hevc_dcr` `image` `mp3_frame` `mpeg_asc` `mpeg_pes_packet` `mpeg_spu` `opus_packet` `vorbis_packet` `vp8_frame` `vp9_cfm` `vp9_frame`| +|[`moc3`](#moc3) |MOC3 file || +|[`mp3`](#mp3) |MP3 file |`id3v2` `id3v1` `id3v11` `apev2` `mp3_frame`| +|`mp3_frame` |MPEG audio layer 3 frame |`mp3_frame_tags`| +|`mp3_frame_vbri` |MP3 frame Fraunhofer encoder variable bitrate tag || +|`mp3_frame_xing` |MP3 frame Xing/Info tag || +|[`mp4`](#mp4) |ISOBMFF, QuickTime and similar |`aac_frame` `av1_ccr` `av1_frame` `avc_au` `avc_dcr` `flac_frame` `flac_metadatablocks` `hevc_au` `hevc_dcr` `icc_profile` `id3v2` `image` `jpeg` `mp3_frame` `mpeg_es` `mpeg_pes_packet` `opus_packet` `png` `prores_frame` `protobuf_widevine` `pssh_playready` `vorbis_packet` `vp9_frame` `vpx_ccr`| +|`mpeg_asc` |MPEG-4 Audio Specific Config || +|`mpeg_es` |MPEG Elementary Stream |`mpeg_asc` `vorbis_packet`| +|`mpeg_pes` |MPEG Packetized elementary stream |`mpeg_pes_packet` `mpeg_spu`| +|`mpeg_pes_packet` |MPEG Packetized elementary stream packet || +|`mpeg_spu` |Sub Picture Unit (DVD subtitle) || +|`mpeg_ts` |MPEG Transport Stream || +|[`msgpack`](#msgpack) |MessagePack || +|`ogg` |OGG file |`ogg_page` `vorbis_packet` `opus_packet` `flac_metadatablock` `flac_frame`| +|`ogg_page` |OGG page || +|[`opentimestamps`](#opentimestamps) |OpenTimestamps file || +|`opus_packet` |Opus packet |`vorbis_comment`| +|[`pcap`](#pcap) |PCAP packet capture |`link_frame` `tcp_stream` `ipv4_packet`| +|`pcapng` |PCAPNG packet capture |`link_frame` `tcp_stream` `ipv4_packet`| +|[`pg_btree`](#pg_btree) |PostgreSQL btree index file || +|[`pg_control`](#pg_control) |PostgreSQL control file || +|[`pg_heap`](#pg_heap) |PostgreSQL heap file || +|`png` |Portable Network Graphics file |`icc_profile` `exif`| +|`prores_frame` |Apple ProRes frame || +|[`protobuf`](#protobuf) |Protobuf || +|`protobuf_widevine` |Widevine protobuf |`protobuf`| +|`pssh_playready` |PlayReady PSSH || +|[`rtmp`](#rtmp) |Real-Time Messaging Protocol |`amf0` `mpeg_asc`| +|`sll2_packet` |Linux cooked capture encapsulation v2 |`inet_packet`| +|`sll_packet` |Linux cooked capture encapsulation |`inet_packet`| +|`tar` |Tar archive |`probe`| +|`tcp_segment` |Transmission control protocol segment || +|`tiff` |Tag Image File Format |`icc_profile`| +|[`tls`](#tls) |Transport layer security |`asn1_ber`| +|`toml` |Tom's Obvious, Minimal Language || +|[`tzif`](#tzif) |Time Zone Information Format || +|`udp_datagram` |User datagram protocol |`udp_payload`| +|`vorbis_comment` |Vorbis comment |`flac_picture`| +|`vorbis_packet` |Vorbis packet |`vorbis_comment`| +|`vp8_frame` |VP8 frame || +|`vp9_cfm` |VP9 Codec Feature Metadata || +|`vp9_frame` |VP9 frame || +|`vpx_ccr` |VPX Codec Configuration Record || +|[`wasm`](#wasm) |WebAssembly Binary Format || +|`wav` |WAV file |`id3v2` `id3v1` `id3v11`| +|`webp` |WebP image |`exif` `vp8_frame` `icc_profile` `xml`| +|[`xml`](#xml) |Extensible Markup Language || +|`yaml` |YAML Ain't Markup Language || +|[`zip`](#zip) |ZIP archive |`probe`| +|`image` |Group |`gif` `jpeg` `mp4` `png` `tiff` `webp`| +|`inet_packet` |Group |`ipv4_packet` `ipv6_packet`| +|`ip_packet` |Group |`icmp` `icmpv6` `tcp_segment` `udp_datagram`| +|`link_frame` |Group |`bsd_loopback_frame` `ether8023_frame` `ipv4_packet` `ipv6_packet` `sll2_packet` `sll_packet`| +|`mp3_frame_tags` |Group |`mp3_frame_vbri` `mp3_frame_xing`| +|`probe` |Group |`adts` `aiff` `apple_bookmark` `ar` `avi` `avro_ocf` `bitcoin_blkdat` `bplist` `bzip2` `caff` `elf` `flac` `gif` `gzip` `html` `jpeg` `json` `jsonl` `leveldb_table` `luajit` `macho` `macho_fat` `matroska` `moc3` `mp3` `mp4` `mpeg_ts` `ogg` `opentimestamps` `pcap` `pcapng` `png` `tar` `tiff` `toml` `tzif` `wasm` `wav` `webp` `xml` `yaml` `zip`| +|`tcp_stream` |Group |`dns_tcp` `rtmp` `tls`| +|`udp_payload` |Group |`dns`| [#]: sh-end @@ -691,7 +693,36 @@ $ fq -n -d html '[inputs | {key: input_filename, value: .html.head.title?}] | fr $ fq -r -o array=true -d html '.. | select(.[0] == "a" and .[1].href)?.[1].href' file.html ``` -## leveldb_ldb +## leveldb_descriptor + +### Limitations + +- fragmented non-"full" records are not merged and decoded further. + +### Authors + +- [@mikez](https://github.com/mikez), original author + +### References + +- https://github.com/google/leveldb/blob/main/doc/impl.md#manifest +- https://github.com/google/leveldb/blob/main/db/version_edit.cc + +## leveldb_log + +### Limitations + +- fragmented non-"full" records are not merged and decoded further. + +### Authors + +- [@mikez](https://github.com/mikez), original author + +### References + +- https://github.com/google/leveldb/blob/main/doc/log_format.md + +## leveldb_table ### Limitations diff --git a/format/leveldb/testdata/leveldb_manifest_torepr.fqtest b/format/leveldb/testdata/leveldb_manifest_torepr.fqtest new file mode 100644 index 00000000..3e2fac9a --- /dev/null +++ b/format/leveldb/testdata/leveldb_manifest_torepr.fqtest @@ -0,0 +1,39 @@ +$ fq -d leveldb_descriptor torepr uncompressed.ldb/MANIFEST-000004 +[ + [ + { + "comparator": "leveldb.BytewiseComparator" + } + ], + [ + { + "log_number": 6 + }, + { + "previous_log_number": 0 + }, + { + "next_file_number": 7 + }, + { + "last_sequence": 4 + }, + { + "new_file": { + "file_number": 5, + "file_size": 1626, + "largest_internal_key": { + "sequence_number": 4, + "type": "value", + "user_key": "row" + }, + "level": 0, + "smallest_internal_key": { + "sequence_number": 3, + "type": "value", + "user_key": "lorem.dolor" + } + } + } + ] +]