Skip to main content

max / shop

Bound the state shop-vt holds for an incomplete sequence Three accumulators grew for as long as a writer kept writing, and a terminal's writer is whatever program holds the far end of the PTY: a crafted file through cat, a compromised build script, an ssh session to a hostile host. Measured by the soak oracle on 2026-08-29, ESC [ and four million separators retained 27.2 bytes of buffer per input byte, so roughly 19 MB of hostile stdout retained a gigabyte. Unterminated OSC and APC bodies accumulated 1:1 with no ceiling at all. - MAX_PARAMS = 32 caps CSI and DCS parameter slots, subparameters included. Past it the sequence dispatches with ignore=true and the extra slots are dropped, which is what the reference DEC parser does with its fixed store and what this parser already did with a third intermediate. 32 is vte's number, and this crate exists to be a drop-in for vte with an APC callback, so an application that renders under one renders under the other. xterm's NPARAM is 30; the widest real sequence is a 6-slot 38:2::R:G:B. - MAX_STRING_BYTES = 8 MiB caps an OSC or APC body. Over it the body is dropped rather than truncated: half a base64 clipboard write is a different request, not a smaller one. The kitty graphics protocol requires payloads over 4096 bytes to be chunked, so an APC body is kilobytes; OSC 52 is the only field with real size to it. - MAX_OSC_PARAMS = 1024 caps the OSC field table, separately because a separator costs a 16-byte index pair and contributes no body byte to charge against the byte budget. The body buffers shrink back to their 2 KiB resting size when a sequence ends. Capacity is a high-water mark, so without that the caps would bound one sequence rather than the process. The oracle now asserts both halves of the finding. MAX_RETAINED_PER_INPUT_BYTE drops 128 to 4, set from the measured worst case of a buffer caught just past a doubling; the same four million separators now retain 0.001 bytes per input byte. A ratio can never see a 1:1 accumulator, so MAX_RETAINED_BYTES is new: an absolute 12 MiB ceiling computed from the caps, which is what catches a body that grows with a stream nobody terminates. Both were verified against the pre-cap parser: the CSI witness trips the ratio, the string witnesses trip the absolute. Three inputs in fuzz/regressions/ and a replay in tests/regressions.rs that feeds bodies twice the cap, which is a size no committed file should carry. Closes the shop-grid half of the 2026-08-29 soak finding.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01DwpiantpUgohzML4xr6KeQ
Author: Max Johnson <me@maxj.phd> · 2026-08-30 12:47 UTC
Signed with PGP, not checked
Commit: f5ae421a7971b45002349c1670b724f401b206b5
Parent: 66d340d
7 files changed, +372 insertions, -50 deletions
M Cargo.lock +4 -4
@@ -2390,6 +2390,10 @@
2390 2390 name = "synckit-config"
2391 2391 version = "0.2.0"
2392 2392
2393 + [[patch.unused]]
2394 + name = "docengine"
2395 + version = "0.7.0"
2396 +
2393 2397 [[patch.unused]]
2394 2398 name = "quasi-axum"
2395 2399 version = "0.81.0"
@@ -2441,7 +2445,3 @@
2441 2445 [[patch.unused]]
2442 2446 name = "tagtree"
2443 2447 version = "0.4.1"
2444 -
2445 - [[patch.unused]]
2446 - name = "docengine"
2447 - version = "0.7.0"
@@ -31,8 +31,11 @@
31 31 //! second drain with no input in between reports nothing.
32 32 //! 5. **Resize keeps all of the above**, including a resize back to the
33 33 //! original size, which is where `rewrap_history` runs.
34 - //! 6. **The parser's buffers are bounded by the input** — an amplification
35 - //! ceiling, not a fix. See [`MAX_RETAINED_PER_INPUT_BYTE`].
34 + //! 6. **The parser's buffers are bounded**, twice over: by the input, via
35 + //! [`MAX_RETAINED_PER_INPUT_BYTE`], and absolutely, via
36 + //! [`MAX_RETAINED_BYTES`]. The second is the one that catches an
37 + //! accumulator growing 1:1 with a stream nobody terminates, which the
38 + //! first cannot see.
36 39 //! 7. **Ground is always reachable** — after any byte sequence, `ESC \` then
37 40 //! `ESC [ 0 m` returns the parser to Ground from every state. Cheap, and it
38 41 //! catches a transition-table edit that strands a stream.
@@ -43,27 +46,40 @@
43 46 /// Bytes the parser may hold per byte of input before the oracle calls it a
44 47 /// finding.
45 48 ///
46 - /// Not a claim that the current parser is frugal. Measured on 2026-08-29, an
47 - /// `ESC [` followed by four million separators retains 27.2 bytes of buffer
48 - /// capacity per input byte, because every `;` pushes a fresh `Vec<u16>` and
49 - /// nothing caps the count; counted as process RSS, with the allocator's own
50 - /// per-allocation overhead, the same input costs about twice that. An
51 - /// unterminated OSC or APC body accumulates 1:1 with no cap either. Those are a
52 - /// denial of service and are reported as one; they are deliberately NOT what
53 - /// this constant asserts, because a ceiling set below today's behaviour makes
54 - /// the target report the same known finding on every input forever and never
55 - /// reach anything new.
49 + /// This is now an assertion rather than a placeholder. It sat at 128 until
50 + /// 2026-08-30, deliberately above a parser that had no ceiling at all: `ESC [`
51 + /// followed by four million separators retained 27.2 bytes per input byte
52 + /// because every `;` pushed a fresh `Vec<u16>`, and an unterminated OSC or APC
53 + /// body accumulated 1:1 forever. `shop_vt::MAX_PARAMS`,
54 + /// `shop_vt::MAX_STRING_BYTES` and `shop_vt::MAX_OSC_PARAMS` closed all three.
56 55 ///
57 - /// What it does catch is a regression that makes the amplification worse, or an
58 - /// accumulator that grows without the input growing. Lower it when the
59 - /// allocation finding is fixed; that is the point at which it starts asserting
60 - /// something the code does not already satisfy.
61 - pub const MAX_RETAINED_PER_INPUT_BYTE: usize = 128;
56 + /// 4 is set from the measured worst case, which is a body buffer caught just
57 + /// past a doubling: 2.0 bytes of capacity per byte pushed, plus the parameter
58 + /// list and the OSC index table on top. The same four million separators now
59 + /// retain 0.001 bytes per input byte. Anything that pushes this back over 4 is
60 + /// either a new accumulator or a cap that stopped being enforced.
61 + pub const MAX_RETAINED_PER_INPUT_BYTE: usize = 4;
62 62
63 - /// Slack for the buffers a fresh parser allocates up front (two 2 KiB bodies)
64 - /// plus the parameter list's own spine.
63 + /// Slack for the buffers a fresh parser allocates up front (two 2 KiB bodies),
64 + /// the parameter list's own spine, and the OSC field index table, which costs
65 + /// 16 bytes per `;` and so amplifies hard against a stream of nothing else.
65 66 pub const RETAINED_BASE_BYTES: usize = 64 * 1024;
66 67
68 + /// Bytes the parser may hold after any input at all, however long.
69 + ///
70 + /// The ratio ceiling above cannot see the second half of the 2026-08-29
71 + /// finding. An unterminated OSC or APC body accumulated 1:1, so its ratio was
72 + /// 1.0 and no per-input-byte limit above 1 would ever have fired, while the
73 + /// buffer grew for as long as the writer kept writing. What was wrong with it
74 + /// was that it had no absolute bound, and this is that bound.
75 + ///
76 + /// Set from the caps rather than guessed: one body buffer at
77 + /// `shop_vt::MAX_STRING_BYTES`, the other resting at its initial 2 KiB, the OSC
78 + /// index table at `shop_vt::MAX_OSC_PARAMS` doubled, and `shop_vt::MAX_PARAMS`
79 + /// slots. That is about 8.42 MiB; 12 MiB leaves room for allocator rounding
80 + /// without leaving room for an accumulator that does not stop.
81 + pub const MAX_RETAINED_BYTES: usize = 12 * 1024 * 1024;
82 +
67 83 /// Panics if `grid` has broken anything `place_char`'s unchecked store rests on.
68 84 ///
69 85 /// # Panics
@@ -251,6 +267,10 @@
251 267 "parser holds {retained} bytes after {} bytes of input, over the {ceiling} ceiling",
252 268 stream.len()
253 269 );
270 + assert!(
271 + retained <= MAX_RETAINED_BYTES,
272 + "parser holds {retained} bytes, over the {MAX_RETAINED_BYTES} absolute ceiling"
273 + );
254 274
255 275 // Ground is reachable from every state these two sequences can leave the
256 276 // parser in: `ESC \` closes any string state, and a complete CSI closes the
@@ -75,3 +75,35 @@
75 75 let input = b"\x63\x1dhello\x1b[31mworld\x1b[H\x1b[2J";
76 76 assert_eq!(shop_grid::oracle::check_bytes(input), input.len() - 2);
77 77 }
78 +
79 + /// The two unbounded growths the parser had until 2026-08-30, replayed at a
80 + /// size the committed corpus cannot carry.
81 + ///
82 + /// `fuzz/regressions/` holds an 8 KiB witness for each, which is enough for the
83 + /// amplification ceiling to catch the CSI case. Neither string case amplifies —
84 + /// they accumulated 1:1 — so the only thing that fails on an uncapped parser is
85 + /// feeding it more than the cap, and eight megabytes is not a file to commit.
86 + #[test]
87 + fn unbounded_parser_growth_stays_capped() {
88 + // Four million separators, each of which used to push a fresh Vec<u16>.
89 + // The oracle reads the first two bytes as the grid size, not as stream.
90 + let mut csi = b"\x4f\x17\x1b[".to_vec();
91 + csi.extend(std::iter::repeat_n(b';', 4_000_000));
92 + shop_grid::oracle::check_bytes(&csi);
93 +
94 + // Bodies twice the cap, opened and never terminated.
95 + let over = shop_vt::MAX_STRING_BYTES * 2;
96 + for opener in [&b"\x4f\x17\x1b]"[..], &b"\x4f\x17\x1b_"[..]] {
97 + let mut body = opener.to_vec();
98 + body.extend(std::iter::repeat_n(b'A', over));
99 + shop_grid::oracle::check_bytes(&body);
100 + }
101 +
102 + // And the buffers come back down afterwards rather than holding the cap
103 + // for the life of the parser, which is what makes the ceiling hold for
104 + // every input that follows a big one.
105 + let mut big = b"\x4f\x17\x1b]0;".to_vec();
106 + big.extend(std::iter::repeat_n(b'A', over));
107 + big.extend_from_slice(b"\x07\x1b[0m");
108 + shop_grid::oracle::check_bytes(&big);
109 + }
@@ -9,7 +9,13 @@
9 9 //! Deliberately narrow scope:
10 10 //! - Written from the spec (not vendored from vte).
11 11 //! - Params live in `Vec<Vec<u16>>` for clarity; not the tightest packing but
12 - //! trivial to iterate and terminals do not push millions of CSIs per sec.
12 + //! trivial to iterate. This used to add "and terminals do not push millions
13 + //! of CSIs per sec", which was a statement about well-behaved writers and not
14 + //! about the ones the parser actually has to survive. See [`MAX_PARAMS`].
15 + //! - State the parser holds on behalf of an incomplete sequence is bounded:
16 + //! [`MAX_PARAMS`], [`MAX_STRING_BYTES`] and [`MAX_OSC_PARAMS`]. Nothing here
17 + //! grows with what a writer sends, because the writer is whatever program
18 + //! holds the far end of the PTY.
13 19 //! - No SIMD UTF-8 fast path yet — that's a `simdutf8` swap when we care.
14 20 //! - No sync-update (BSU/ESU) hooks yet — added when someone starts using
15 21 //! them and paint tearing shows up.
@@ -69,6 +75,55 @@
69 75 }
70 76 }
71 77
78 + /// Parameter slots a single CSI or DCS sequence may hold, counting
79 + /// subparameters.
80 + ///
81 + /// Past this the sequence is marked ignored and the extra slots are dropped,
82 + /// which is what the reference DEC parser does with its own fixed parameter
83 + /// store and what this parser already does with a third intermediate. Without
84 + /// it every `;` pushes a fresh `Vec<u16>` for as long as a writer keeps
85 + /// sending them: measured 2026-08-29, `ESC [` and four million separators
86 + /// retained 27.2 bytes of buffer per input byte, so about 19 MB of hostile
87 + /// stdout retained a gigabyte.
88 + ///
89 + /// 32 is `vte`'s number, and this crate exists to be a drop-in for `vte` with
90 + /// an APC callback, so matching it means an application that renders under one
91 + /// renders under the other. xterm's NPARAM is 30, and the widest real sequence
92 + /// anyone sends is a 6-slot `38:2::R:G:B`.
93 + pub const MAX_PARAMS: usize = 32;
94 +
95 + /// Bytes an OSC or APC body may accumulate before the parser stops buffering
96 + /// and drops the sequence.
97 + ///
98 + /// Unterminated bodies accumulated 1:1 with no ceiling at all, so a writer that
99 + /// opens `ESC ]` and never terminates it grew the terminal by whatever it felt
100 + /// like sending.
101 + ///
102 + /// 8 MiB is far above anything either protocol asks for. The kitty graphics
103 + /// protocol requires payloads over 4096 bytes to be chunked, so an APC body is
104 + /// a few kilobytes; OSC 52 carries a base64 clipboard selection, which is the
105 + /// one field with any real size to it. A body over the limit is dropped rather
106 + /// than truncated: half a base64 clipboard write or half an image chunk is not
107 + /// a smaller version of the request, it is a different one.
108 + pub const MAX_STRING_BYTES: usize = 8 * 1024 * 1024;
109 +
110 + /// Fields (`;`-separated) an OSC body may hold before the sequence is dropped.
111 + ///
112 + /// Separated from [`MAX_STRING_BYTES`] because a separator costs 16 bytes of
113 + /// index pair and contributes no body byte, so a stream of nothing but `;`
114 + /// amplifies about 32x against the byte budget. 1024 is past any real OSC:
115 + /// the widest is a multi-colour `OSC 4`, and shop's own handler reads two
116 + /// fields.
117 + pub const MAX_OSC_PARAMS: usize = 1024;
118 +
119 + /// What the two body buffers are allocated with, and shrunk back to once a
120 + /// sequence ends.
121 + ///
122 + /// Shrinking is the half that makes the cap hold across sequences: capacity is
123 + /// a high-water mark, so without it one large body leaves the parser holding
124 + /// that much for the life of the terminal.
125 + const INITIAL_BODY_CAPACITY: usize = 2048;
126 +
72 127 /// Iterable parameter list for CSI / DCS. Each iteration yields one
73 128 /// parameter's subparameters (colon-separated, e.g. `38:2::R:G:B` gives one
74 129 /// entry `[38, 2, 0, R, G, B]`; `38;2;R;G;B` gives five entries `[38] [2]
@@ -76,6 +131,9 @@
76 131 #[derive(Debug, Default, Clone)]
77 132 pub struct Params {
78 133 inner: Vec<Vec<u16>>,
134 + /// Slots used across every group, which is what [`MAX_PARAMS`] bounds.
135 + /// Held rather than summed because it is consulted per byte.
136 + slots: usize,
79 137 }
80 138
81 139 impl Params {
@@ -93,20 +151,36 @@
93 151
94 152 fn clear(&mut self) {
95 153 self.inner.clear();
154 + self.slots = 0;
96 155 }
97 156
98 - fn push_new(&mut self) {
99 - self.inner.push(Vec::with_capacity(1));
157 + fn is_full(&self) -> bool {
158 + self.slots >= MAX_PARAMS
100 159 }
101 160
102 - fn ensure_open(&mut self) {
103 - if self.inner.is_empty() {
104 - self.push_new();
161 + /// Opens a group, or reports that the sequence has run out of slots.
162 + fn push_new(&mut self) -> bool {
163 + if self.is_full() {
164 + return false;
105 165 }
166 + self.inner.push(Vec::with_capacity(1));
167 + self.slots += 1;
168 + true
106 169 }
107 170
171 + fn ensure_open(&mut self) -> bool {
172 + if self.inner.is_empty() {
173 + return self.push_new();
174 + }
175 + true
176 + }
177 +
178 + /// Digits only ever rewrite the slot already open, so this cannot grow the
179 + /// list and does not report an overflow of its own.
108 180 fn append_digit(&mut self, digit: u16) {
109 - self.ensure_open();
181 + if !self.ensure_open() {
182 + return;
183 + }
110 184 let group = self.inner.last_mut().unwrap();
111 185 if group.is_empty() {
112 186 group.push(digit);
@@ -116,13 +190,20 @@
116 190 }
117 191 }
118 192
119 - fn new_subparam(&mut self) {
120 - self.ensure_open();
193 + fn new_subparam(&mut self) -> bool {
194 + if !self.ensure_open() {
195 + return false;
196 + }
197 + if self.is_full() {
198 + return false;
199 + }
121 200 self.inner.last_mut().unwrap().push(0);
201 + self.slots += 1;
202 + true
122 203 }
123 204
124 - fn new_param(&mut self) {
125 - self.push_new();
205 + fn new_param(&mut self) -> bool {
206 + self.push_new()
126 207 }
127 208
128 209 /// Heap bytes this parameter list is holding.
@@ -172,6 +253,10 @@
172 253 osc_buf: Vec<u8>,
173 254 osc_params: Vec<(usize, usize)>,
174 255 apc_buf: Vec<u8>,
256 + /// Set when the open OSC or APC body has passed [`MAX_STRING_BYTES`] or
257 + /// [`MAX_OSC_PARAMS`]. The parser keeps scanning for the terminator so the
258 + /// stream stays in sync, buffers nothing more, and dispatches nothing.
259 + string_overflow: bool,
175 260 utf8_buf: [u8; 4],
176 261 utf8_idx: usize,
177 262 utf8_expected: usize,
@@ -192,9 +277,10 @@
192 277 intermediates_idx: 0,
193 278 ignoring: false,
194 279 params: Params::default(),
195 - osc_buf: Vec::with_capacity(2048),
280 + osc_buf: Vec::with_capacity(INITIAL_BODY_CAPACITY),
196 281 osc_params: Vec::with_capacity(8),
197 - apc_buf: Vec::with_capacity(2048),
282 + apc_buf: Vec::with_capacity(INITIAL_BODY_CAPACITY),
283 + string_overflow: false,
198 284 utf8_buf: [0; 4],
199 285 utf8_idx: 0,
200 286 utf8_expected: 0,
@@ -302,7 +388,7 @@
302 388 self.state = State::DcsEntry;
303 389 }
304 390 0x58 | 0x5E => {
305 - self.apc_buf.clear();
391 + self.apc_start();
306 392 self.state = State::ApcString;
307 393 }
308 394 0x5B => {
@@ -314,7 +400,7 @@
314 400 self.state = State::OscString;
315 401 }
316 402 0x5F => {
317 - self.apc_buf.clear();
403 + self.apc_start();
318 404 self.state = State::ApcString;
319 405 }
320 406 0x7F => {} // Ignore.
@@ -356,11 +442,15 @@
356 442 self.state = State::CsiParam;
357 443 }
358 444 0x3A => {
359 - self.params.new_subparam();
445 + if !self.params.new_subparam() {
446 + self.ignoring = true;
447 + }
360 448 self.state = State::CsiParam;
361 449 }
362 450 0x3B => {
363 - self.params.new_param();
451 + if !self.params.new_param() {
452 + self.ignoring = true;
453 + }
364 454 self.state = State::CsiParam;
365 455 }
366 456 0x3C..=0x3F => {
@@ -389,8 +479,16 @@
389 479 self.state = State::CsiIntermediate;
390 480 }
391 481 0x30..=0x39 => self.params.append_digit((b - b'0') as u16),
392 - 0x3A => self.params.new_subparam(),
393 - 0x3B => self.params.new_param(),
482 + 0x3A => {
483 + if !self.params.new_subparam() {
484 + self.ignoring = true;
485 + }
486 + }
487 + 0x3B => {
488 + if !self.params.new_param() {
489 + self.ignoring = true;
490 + }
491 + }
394 492 0x3C..=0x3F => self.state = State::CsiIgnore,
395 493 0x40..=0x7E => {
396 494 perform.csi_dispatch(
@@ -438,6 +536,7 @@
438 536 0x07 => {
439 537 self.osc_close_current();
440 538 self.dispatch_osc(perform, true);
539 + self.osc_end();
441 540 self.state = State::Ground;
442 541 }
443 542 0x1B => {
@@ -445,28 +544,53 @@
445 544 // following `\` gets consumed as a no-op esc_dispatch.
446 545 self.osc_close_current();
447 546 self.dispatch_osc(perform, false);
547 + self.osc_end();
448 548 self.prev_string_state = State::OscString;
449 549 self.state = State::Escape;
450 550 self.clear();
451 551 }
452 552 0x3B => {
453 553 // Parameter separator: close current field, open next.
554 + if self.osc_params.len() >= MAX_OSC_PARAMS {
555 + self.string_overflow = true;
556 + return;
557 + }
454 558 self.osc_close_current();
455 559 let end = self.osc_buf.len();
456 560 self.osc_params.push((end, end));
457 561 }
458 - _ => self.osc_buf.push(b),
562 + _ => {
563 + if self.osc_buf.len() >= MAX_STRING_BYTES {
564 + self.string_overflow = true;
565 + return;
566 + }
567 + self.osc_buf.push(b);
568 + }
459 569 }
460 570 }
461 571
462 572 fn osc_start(&mut self) {
463 573 self.osc_buf.clear();
464 574 self.osc_params.clear();
575 + self.string_overflow = false;
465 576 // Open the first parameter with a placeholder end index that
466 577 // `osc_close_current` finalizes on ; / BEL / ST.
467 578 self.osc_params.push((0, 0));
468 579 }
469 580
581 + /// Returns the OSC buffers to their resting size once a body has ended.
582 + ///
583 + /// `clear` leaves capacity behind, so a single oversized body would keep
584 + /// the cap's worth of memory reserved for the life of the parser and the
585 + /// limit above would bound one sequence rather than the process.
586 + fn osc_end(&mut self) {
587 + self.osc_buf.clear();
588 + self.osc_buf.shrink_to(INITIAL_BODY_CAPACITY);
589 + self.osc_params.clear();
590 + self.osc_params.shrink_to(8);
591 + self.string_overflow = false;
592 + }
593 +
470 594 fn osc_close_current(&mut self) {
471 595 if let Some(last) = self.osc_params.last_mut() {
472 596 last.1 = self.osc_buf.len();
@@ -474,6 +598,11 @@
474 598 }
475 599
476 600 fn dispatch_osc<P: Perform>(&self, perform: &mut P, bell_terminated: bool) {
601 + // An over-long body is dropped, not truncated: half a base64 clipboard
602 + // write is a different request, not a smaller one.
603 + if self.string_overflow {
604 + return;
605 + }
477 606 let slices: Vec<&[u8]> = self
478 607 .osc_params
479 608 .iter()
@@ -495,7 +624,9 @@
495 624 }
496 625 0x3A => self.state = State::DcsIgnore,
497 626 0x3B => {
498 - self.params.new_param();
627 + if !self.params.new_param() {
628 + self.ignoring = true;
629 + }
499 630 self.state = State::DcsParam;
500 631 }
501 632 0x3C..=0x3F => {
@@ -525,7 +656,11 @@
525 656 }
526 657 0x30..=0x39 => self.params.append_digit((b - b'0') as u16),
527 658 0x3A => self.state = State::DcsIgnore,
528 - 0x3B => self.params.new_param(),
659 + 0x3B => {
660 + if !self.params.new_param() {
661 + self.ignoring = true;
662 + }
663 + }
529 664 0x3C..=0x3F => self.state = State::DcsIgnore,
530 665 0x40..=0x7E => {
531 666 perform.hook(
@@ -589,21 +724,44 @@
589 724 fn apc_string<P: Perform>(&mut self, perform: &mut P, b: u8) {
590 725 match b {
591 726 0x07 => {
592 - perform.apc_dispatch(&self.apc_buf);
593 - self.apc_buf.clear();
727 + if !self.string_overflow {
728 + perform.apc_dispatch(&self.apc_buf);
729 + }
730 + self.apc_end();
594 731 self.state = State::Ground;
595 732 }
596 733 0x1B => {
597 - perform.apc_dispatch(&self.apc_buf);
598 - self.apc_buf.clear();
734 + if !self.string_overflow {
735 + perform.apc_dispatch(&self.apc_buf);
736 + }
737 + self.apc_end();
599 738 self.prev_string_state = State::ApcString;
600 739 self.state = State::Escape;
601 740 self.clear();
602 741 }
603 - _ => self.apc_buf.push(b),
742 + _ => {
743 + if self.apc_buf.len() >= MAX_STRING_BYTES {
744 + self.string_overflow = true;
745 + return;
746 + }
747 + self.apc_buf.push(b);
748 + }
604 749 }
605 750 }
606 751
752 + /// Opens an APC body. Paired with [`Parser::apc_end`] for the same reason
753 + /// [`Parser::osc_start`] is paired with [`Parser::osc_end`].
754 + fn apc_start(&mut self) {
755 + self.apc_buf.clear();
756 + self.string_overflow = false;
757 + }
758 +
759 + fn apc_end(&mut self) {
760 + self.apc_buf.clear();
761 + self.apc_buf.shrink_to(INITIAL_BODY_CAPACITY);
762 + self.string_overflow = false;
763 + }
764 +
607 765 /// Is the parser between sequences, holding no partial state?
608 766 ///
609 767 /// Ground is the only state in which a stream can be cut without losing
@@ -894,4 +1052,113 @@
894 1052 "dispatch should carry ignore=true, got {events:?}"
895 1053 );
896 1054 }
1055 +
1056 + // ---- Bounded state (the 2026-08-29 DoS finding) --------------------
1057 +
1058 + /// A CSI with more parameters than the list holds dispatches with the
1059 + /// ignore flag set, exactly as a third intermediate already does, and stops
1060 + /// growing.
1061 + #[test]
1062 + fn csi_past_the_parameter_cap_is_ignored_not_buffered() {
1063 + let mut p = Parser::new();
1064 + let mut r = Rec::default();
1065 + let mut seq = b"\x1b[".to_vec();
1066 + seq.extend(std::iter::repeat_n(b';', 100_000));
1067 + seq.push(b'm');
1068 + p.advance(&mut r, &seq);
1069 +
1070 + let event = r.0.last().expect("a dispatch").clone();
1071 + assert!(event.contains("ignore=true"), "got {event}");
1072 + assert!(
1073 + p.buffered_bytes() < 8 * 1024,
1074 + "parser kept {} bytes for 100k separators",
1075 + p.buffered_bytes()
1076 + );
1077 + assert!(p.in_ground());
1078 + }
1079 +
1080 + /// Parameters up to the cap still arrive, so the cap changes nothing for
1081 + /// anything anyone sends.
1082 + #[test]
1083 + fn csi_at_the_parameter_cap_still_dispatches_every_slot() {
1084 + let params: Vec<String> = (1..=MAX_PARAMS).map(|n| n.to_string()).collect();
1085 + let events = run(format!("\x1b[{}m", params.join(";")).as_bytes());
1086 +
1087 + let event = events.last().expect("a dispatch");
1088 + assert!(event.contains("ignore=false"), "got {event}");
1089 + assert!(event.contains(&format!("[{MAX_PARAMS}]")), "got {event}");
1090 + }
1091 +
1092 + /// An over-long OSC body is dropped rather than truncated, and the buffer
1093 + /// it grew goes back down.
1094 + ///
1095 + /// Dropped because half a base64 clipboard write is a different request,
1096 + /// not a smaller one; shrunk because capacity is a high-water mark, and
1097 + /// without that the cap would bound one sequence rather than the process.
1098 + #[test]
1099 + fn an_oversized_osc_body_is_dropped_and_the_buffer_shrinks() {
1100 + let mut p = Parser::new();
1101 + let mut r = Rec::default();
1102 + let mut seq = b"\x1b]0;".to_vec();
1103 + seq.extend(std::iter::repeat_n(b'A', MAX_STRING_BYTES + 1));
1104 + seq.push(0x07);
1105 + p.advance(&mut r, &seq);
1106 +
1107 + assert!(
1108 + r.0.is_empty(),
1109 + "a body over the cap should dispatch nothing, got {:?}",
1110 + r.0
1111 + );
1112 + assert!(
1113 + p.buffered_bytes() < 8 * 1024,
1114 + "buffers stayed at {} bytes after the body ended",
1115 + p.buffered_bytes()
1116 + );
1117 + assert!(p.in_ground());
1118 + }
1119 +
1120 + /// A body under the cap is unaffected, including one large enough to have
1121 + /// grown the buffer well past its resting size.
1122 + #[test]
1123 + fn an_ordinary_osc_body_still_dispatches() {
1124 + let title = "t".repeat(100_000);
1125 + let events = run(format!("\x1b]0;{title}\x07").as_bytes());
1126 + assert_eq!(events.len(), 1, "got {events:?}");
1127 + assert!(events[0].starts_with("osc("), "got {events:?}");
1128 + }
1129 +
1130 + /// The OSC field table is bounded on its own account, because a separator
1131 + /// costs an index pair and contributes no body byte to charge it against.
1132 + #[test]
1133 + fn osc_separators_alone_do_not_grow_the_field_table() {
1134 + let mut p = Parser::new();
1135 + let mut r = Rec::default();
1136 + let mut seq = b"\x1b]".to_vec();
1137 + seq.extend(std::iter::repeat_n(b';', 100_000));
1138 + seq.push(0x07);
1139 + p.advance(&mut r, &seq);
1140 +
1141 + assert!(r.0.is_empty(), "got {:?}", r.0);
1142 + assert!(
1143 + p.buffered_bytes() < 64 * 1024,
1144 + "parser kept {} bytes for 100k separators",
1145 + p.buffered_bytes()
1146 + );
1147 + }
1148 +
1149 + /// The APC body has the same ceiling. This is the one the kitty graphics
1150 + /// protocol arrives through, and the protocol requires payloads over 4096
1151 + /// bytes to be chunked, so nothing legitimate comes near it.
1152 + #[test]
1153 + fn an_oversized_apc_body_is_dropped() {
1154 + let mut p = Parser::new();
1155 + let mut r = Rec::default();
1156 + let mut seq = b"\x1b_G".to_vec();
1157 + seq.extend(std::iter::repeat_n(b'A', MAX_STRING_BYTES + 1));
1158 + seq.extend_from_slice(b"\x1b\\");
1159 + p.advance(&mut r, &seq);
1160 +
1161 + assert!(!r.0.iter().any(|e| e.starts_with("apc(")), "got {:?}", r.0);
1162 + assert!(p.buffered_bytes() < 8 * 1024);
1163 + }
897 1164 }
@@ -1,0 +1,1 @@
1 + O_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@@ -1,0 +1,1 @@
1 + O[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1,0 +1,1 @@
1 + O]AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA