detached 2ef4850

fix(vt): address wrap-up review of the allocation pass

ansi: a stale commit or Reset now invalidates every outstanding draw, so committing a newer delta cannot re-establish a shadow that disagrees with the terminal; docs match. Drop core.RowsEqual (RowsEqualAt covers it), bounds-check payload IDs in RowsEqualAt, route Frame dispatch through asFrame.

graphics: owned assets with large spare capacity are copied to their exact length, so base64 input padded with CR/LF or zlib read buffers cannot retain memory beyond MaxEncodedBytes.

history: recycle tail storage for default chunks up to 512 columns. vt: drop eviction scratch sized for a much wider past geometry.

html: invalid color kinds return a plain error and invalid UTF-8 tests compare decoded text, so tests no longer depend on the encoding/json implementation; cap the output buffer hint at the byte limit; add FuzzAppendJSONString; drop a duplicate aliasing test.

oracle: one digest per layer (input, vt, graphics, history, ansi, ansi256, html), per-scenario comparison naming the moved layers, refuse partial -oracle.update, run a sixth of the scenarios under -race. The regenerated golden is identical before and after these fixes. Document the oracle, the borrowed/owned byte APIs and the tail recycling decision.
commit
2ef4850759b86b18f62369645a2a9b0c0afe0112
author
brice · · 2026-10-02 13:02 UTC
parent
f8f97be
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
25 files · +829 -585
M README.md +8 -0
@@ -154,6 +154,14 @@ npm run test:browser
154154 npm run test:browser:docker
155155 ```
156156
157+`TestDifferentialOracle` replays seeded terminal workloads through the public
158+VT, history, graphics, ANSI and HTML APIs and compares one digest per layer with
159+`testdata/oracle/golden.txt`. Keep it unchanged for refactors and performance
160+work. For a deliberate behavior change, regenerate it on a full run with
161+`go test -run TestDifferentialOracle -oracle.update .` and explain the changed
162+columns. To locate a divergence, run `-oracle.dump=DIR` on both trees and diff
163+the scenario transcripts.
164+
157165 Playwright 1.62.1 and its Chromium, Firefox, and WebKit revisions are pinned by
158166 `package-lock.json`. The matching Playwright container provides the reproducible
159167 fallback when host libraries cannot run one of those browser builds. Production
@@ -154,6 +154,14 @@ npm run test:browser
154 npm run test:browser:docker154 npm run test:browser:docker
155 ```155 ```
156 156
157+`TestDifferentialOracle` replays seeded terminal workloads through the public
158+VT, history, graphics, ANSI and HTML APIs and compares one digest per layer with
159+`testdata/oracle/golden.txt`. Keep it unchanged for refactors and performance
160+work. For a deliberate behavior change, regenerate it on a full run with
161+`go test -run TestDifferentialOracle -oracle.update .` and explain the changed
162+columns. To locate a divergence, run `-oracle.dump=DIR` on both trees and diff
163+the scenario transcripts.
164+
157 Playwright 1.62.1 and its Chromium, Firefox, and WebKit revisions are pinned by165 Playwright 1.62.1 and its Chromium, Firefox, and WebKit revisions are pinned by
158 `package-lock.json`. The matching Playwright container provides the reproducible166 `package-lock.json`. The matching Playwright container provides the reproducible
159 fallback when host libraries cannot run one of those browser builds. Production167 fallback when host libraries cannot run one of those browser builds. Production
M ansi/delta_plan.go +4 -4
@@ -117,13 +117,13 @@ func planSingleDamage(frame CellSource, d Damage) DeltaPlan {
117117 return plan
118118 }
119119
120-func buildDirtyLinePlan(frame, committed CellSource) ([]Span, bool) {
120+func buildDirtyLinePlan(frame CellSource, committed Frame) ([]Span, bool) {
121121 var spans []Span
122- fast, fastOK := compactFrames(frame, committed)
122+ dense, isDense := asFrame(frame)
123123 for y := range frame.Rows() {
124124 dirty := false
125- if fastOK {
126- dirty = !core.RowsEqual(fast.a, fast.b, y)
125+ if isDense {
126+ dirty = !core.RowsEqualAt(dense, y, committed, y)
127127 } else {
128128 for x := range frame.Columns() {
129129 if !frame.Cell(x, y).Equal(committed.Cell(x, y)) {
@@ -117,13 +117,13 @@ func planSingleDamage(frame CellSource, d Damage) DeltaPlan {
117 return plan117 return plan
118 }118 }
119 119
120-func buildDirtyLinePlan(frame, committed CellSource) ([]Span, bool) {120+func buildDirtyLinePlan(frame CellSource, committed Frame) ([]Span, bool) {
121 var spans []Span121 var spans []Span
122- fast, fastOK := compactFrames(frame, committed)122+ dense, isDense := asFrame(frame)
123 for y := range frame.Rows() {123 for y := range frame.Rows() {
124 dirty := false124 dirty := false
125- if fastOK {125+ if isDense {
126- dirty = !core.RowsEqual(fast.a, fast.b, y)126+ dirty = !core.RowsEqualAt(dense, y, committed, y)
127 } else {127 } else {
128 for x := range frame.Columns() {128 for x := range frame.Columns() {
129 if !frame.Cell(x, y).Equal(committed.Cell(x, y)) {129 if !frame.Cell(x, y).Equal(committed.Cell(x, y)) {
M ansi/frame.go +5 -30
@@ -30,10 +30,7 @@ func validateCellSource(source CellSource) error {
3030 if source.Columns() <= 0 || source.Rows() <= 0 {
3131 return fmt.Errorf("invalid cell source size %dx%d", source.Columns(), source.Rows())
3232 }
33- switch frame := source.(type) {
34- case Frame:
35- return frame.Validate()
36- case *Frame:
33+ if frame, ok := asFrame(source); ok {
3734 return frame.Validate()
3835 }
3936 return nil
@@ -48,13 +45,9 @@ func snapshotCellSource(scratch *Frame, source CellSource) Frame {
4845 if scratch == nil {
4946 return cloneCellSource(source)
5047 }
51- switch frame := source.(type) {
52- case Frame:
48+ if frame, ok := asFrame(source); ok {
5349 scratch.CopyFrom(frame)
5450 return *scratch
55- case *Frame:
56- scratch.CopyFrom(*frame)
57- return *scratch
5851 }
5952 columns, rows := source.Columns(), source.Rows()
6053 if scratch.Width != columns || scratch.Height != rows || scratch.Validate() != nil {
@@ -68,23 +61,8 @@ func snapshotCellSource(scratch *Frame, source CellSource) Frame {
6861 return *scratch
6962 }
7063
71-// framePair holds two compact frames compared through core.RowsEqual.
72-type framePair struct{ a, b Frame }
73-
74-// compactFrames reports whether both sources are core.Frame values (directly or
75-// by pointer), enabling stored-cell comparison without the CellSource interface.
76-func compactFrames(a, b CellSource) (framePair, bool) {
77- fa, ok := asFrame(a)
78- if !ok {
79- return framePair{}, false
80- }
81- fb, ok := asFrame(b)
82- if !ok {
83- return framePair{}, false
84- }
85- return framePair{fa, fb}, true
86-}
87-
64+// asFrame reports whether source is a compact core.Frame, directly or through
65+// a non-nil pointer, enabling stored-cell paths that bypass CellSource.
8866 func asFrame(source CellSource) (Frame, bool) {
8967 switch frame := source.(type) {
9068 case Frame:
@@ -98,10 +76,7 @@ func asFrame(source CellSource) (Frame, bool) {
9876 }
9977
10078 func cloneCellSource(source CellSource) Frame {
101- switch frame := source.(type) {
102- case Frame:
103- return frame.Clone()
104- case *Frame:
79+ if frame, ok := asFrame(source); ok {
10580 return frame.Clone()
10681 }
10782 clone := NewFrame(source.Columns(), source.Rows())
@@ -30,10 +30,7 @@ func validateCellSource(source CellSource) error {
30 if source.Columns() <= 0 || source.Rows() <= 0 {30 if source.Columns() <= 0 || source.Rows() <= 0 {
31 return fmt.Errorf("invalid cell source size %dx%d", source.Columns(), source.Rows())31 return fmt.Errorf("invalid cell source size %dx%d", source.Columns(), source.Rows())
32 }32 }
33- switch frame := source.(type) {33+ if frame, ok := asFrame(source); ok {
34- case Frame:
35- return frame.Validate()
36- case *Frame:
37 return frame.Validate()34 return frame.Validate()
38 }35 }
39 return nil36 return nil
@@ -48,13 +45,9 @@ func snapshotCellSource(scratch *Frame, source CellSource) Frame {
48 if scratch == nil {45 if scratch == nil {
49 return cloneCellSource(source)46 return cloneCellSource(source)
50 }47 }
51- switch frame := source.(type) {48+ if frame, ok := asFrame(source); ok {
52- case Frame:
53 scratch.CopyFrom(frame)49 scratch.CopyFrom(frame)
54 return *scratch50 return *scratch
55- case *Frame:
56- scratch.CopyFrom(*frame)
57- return *scratch
58 }51 }
59 columns, rows := source.Columns(), source.Rows()52 columns, rows := source.Columns(), source.Rows()
60 if scratch.Width != columns || scratch.Height != rows || scratch.Validate() != nil {53 if scratch.Width != columns || scratch.Height != rows || scratch.Validate() != nil {
@@ -68,23 +61,8 @@ func snapshotCellSource(scratch *Frame, source CellSource) Frame {
68 return *scratch61 return *scratch
69 }62 }
70 63
71-// framePair holds two compact frames compared through core.RowsEqual.64+// asFrame reports whether source is a compact core.Frame, directly or through
72-type framePair struct{ a, b Frame }65+// a non-nil pointer, enabling stored-cell paths that bypass CellSource.
73-
74-// compactFrames reports whether both sources are core.Frame values (directly or
75-// by pointer), enabling stored-cell comparison without the CellSource interface.
76-func compactFrames(a, b CellSource) (framePair, bool) {
77- fa, ok := asFrame(a)
78- if !ok {
79- return framePair{}, false
80- }
81- fb, ok := asFrame(b)
82- if !ok {
83- return framePair{}, false
84- }
85- return framePair{fa, fb}, true
86-}
87-
88 func asFrame(source CellSource) (Frame, bool) {66 func asFrame(source CellSource) (Frame, bool) {
89 switch frame := source.(type) {67 switch frame := source.(type) {
90 case Frame:68 case Frame:
@@ -98,10 +76,7 @@ func asFrame(source CellSource) (Frame, bool) {
98 }76 }
99 77
100 func cloneCellSource(source CellSource) Frame {78 func cloneCellSource(source CellSource) Frame {
101- switch frame := source.(type) {79+ if frame, ok := asFrame(source); ok {
102- case Frame:
103- return frame.Clone()
104- case *Frame:
105 return frame.Clone()80 return frame.Clone()
106 }81 }
107 clone := NewFrame(source.Columns(), source.Rows())82 clone := NewFrame(source.Columns(), source.Rows())
M ansi/prepared_ownership_test.go +7 -1
@@ -86,7 +86,14 @@ func TestDiscardedPreparedDrawLeavesCommittedStateUnchanged(t *testing.T) {
8686 for y := range committed.Height {
8787 require.Equal(t, committed.Row(y), r.committed.Row(y))
8888 }
89+ // The stale commit invalidated every outstanding draw, so committing
90+ // the newer one cannot re-establish a shadow; the next draw is a
91+ // full snapshot that leaves the shadow exact.
8992 again.Commit()
93+ require.False(t, r.hasCommitted)
94+ snapshot, err := r.Draw(frame, nil)
95+ require.NoError(t, err)
96+ require.NotEmpty(t, snapshot)
9097 require.Equal(t, '#', r.committed.Cell(1, 1).Rune)
9198 require.NoError(t, r.committed.CheckInvariants())
9299
@@ -186,7 +193,6 @@ func TestPrepareCommitDoesNotAllocateFrameStorage(t *testing.T) {
186193 var m1, m2 runtime.MemStats
187194 runtime.ReadMemStats(&m1)
188195 for range 50 {
189- toggled = !toggled
190196 frame.Set(60, 20, Cell{Rune: 'W', Style: DefaultStyle()})
191197 prepared, err := r.Prepare(frame, damage, false)
192198 require.NoError(t, err)
@@ -86,7 +86,14 @@ func TestDiscardedPreparedDrawLeavesCommittedStateUnchanged(t *testing.T) {
86 for y := range committed.Height {86 for y := range committed.Height {
87 require.Equal(t, committed.Row(y), r.committed.Row(y))87 require.Equal(t, committed.Row(y), r.committed.Row(y))
88 }88 }
89+ // The stale commit invalidated every outstanding draw, so committing
90+ // the newer one cannot re-establish a shadow; the next draw is a
91+ // full snapshot that leaves the shadow exact.
89 again.Commit()92 again.Commit()
93+ require.False(t, r.hasCommitted)
94+ snapshot, err := r.Draw(frame, nil)
95+ require.NoError(t, err)
96+ require.NotEmpty(t, snapshot)
90 require.Equal(t, '#', r.committed.Cell(1, 1).Rune)97 require.Equal(t, '#', r.committed.Cell(1, 1).Rune)
91 require.NoError(t, r.committed.CheckInvariants())98 require.NoError(t, r.committed.CheckInvariants())
92 99
@@ -186,7 +193,6 @@ func TestPrepareCommitDoesNotAllocateFrameStorage(t *testing.T) {
186 var m1, m2 runtime.MemStats193 var m1, m2 runtime.MemStats
187 runtime.ReadMemStats(&m1)194 runtime.ReadMemStats(&m1)
188 for range 50 {195 for range 50 {
189- toggled = !toggled
190 frame.Set(60, 20, Cell{Rune: 'W', Style: DefaultStyle()})196 frame.Set(60, 20, Cell{Rune: 'W', Style: DefaultStyle()})
191 prepared, err := r.Prepare(frame, damage, false)197 prepared, err := r.Prepare(frame, damage, false)
192 require.NoError(t, err)198 require.NoError(t, err)
M ansi/renderer.go +20 -8
@@ -51,11 +51,13 @@ func NewWithColorProfile(caps Capabilities, profile ColorProfile) *Renderer {
5151 return &Renderer{caps: caps, colorProfile: profile}
5252 }
5353
54+// Reset forgets the committed shadow and invalidates every outstanding
55+// prepared draw. The private frame buffers are kept for reuse.
5456 func (r *Renderer) Reset() {
5557 r.width = 0
5658 r.height = 0
5759 r.hasCommitted = false
58- // The frame buffers are kept for reuse; hasCommitted gates their content.
60+ r.generation++
5961 }
6062
6163 // Bytes returns the prepared ANSI output. The returned bytes remain valid after
@@ -80,15 +82,24 @@ func (p *PreparedDraw) Commit() {
8082 return
8183 }
8284 if p.generation != r.generation {
83- // A later Prepare reused the scratch frame this draw's snapshot
84- // lives in, so it cannot be applied. Its bytes may nevertheless
85- // have reached the terminal, which would then differ from the
86- // committed shadow in unknown ways: forget the shadow so the next
87- // Prepare emits a full snapshot.
85+ // A later Prepare or Reset reused the scratch frame this draw's
86+ // snapshot lives in, so it cannot be applied. Its bytes may
87+ // nevertheless have reached the terminal, which would then differ
88+ // from the committed shadow in unknown ways: forget the shadow and
89+ // invalidate every outstanding draw, so even a delta prepared
90+ // after this one cannot re-establish a shadow on commit and the
91+ // next Prepare emits a full snapshot.
8892 r.hasCommitted = false
93+ r.generation++
94+ return
95+ }
96+ if !plan.Snapshot && !r.hasCommitted {
97+ // Unreachable for current draws: Prepare plans a snapshot whenever
98+ // no shadow exists, and every path that drops the shadow also
99+ // advances the generation. Keep the shadow dropped defensively.
89100 return
90101 }
91- if plan.Snapshot || !r.hasCommitted {
102+ if plan.Snapshot {
92103 // The snapshot lives in the renderer's scratch buffer; promote it
93104 // and recycle the previous committed buffer as the next scratch.
94105 r.committed, r.scratch = p.candidate.frame, r.committed
@@ -104,7 +115,8 @@ func (p *PreparedDraw) Commit() {
104115 // Prepare plans and encodes a transactional draw. The renderer advances only
105116 // when the returned draw is committed. Keep at most one prepared draw
106117 // outstanding; commit or discard it before calling Prepare again. A draw
107-// superseded by a later Prepare is discarded and its Commit does nothing.
118+// superseded by a later Prepare is not applied: committing it forces the next
119+// Prepare to emit a full snapshot.
108120 //
109121 // The renderer copies frame into reusable private storage, so the caller may
110122 // keep mutating frame between draws.
@@ -51,11 +51,13 @@ func NewWithColorProfile(caps Capabilities, profile ColorProfile) *Renderer {
51 return &Renderer{caps: caps, colorProfile: profile}51 return &Renderer{caps: caps, colorProfile: profile}
52 }52 }
53 53
54+// Reset forgets the committed shadow and invalidates every outstanding
55+// prepared draw. The private frame buffers are kept for reuse.
54 func (r *Renderer) Reset() {56 func (r *Renderer) Reset() {
55 r.width = 057 r.width = 0
56 r.height = 058 r.height = 0
57 r.hasCommitted = false59 r.hasCommitted = false
58- // The frame buffers are kept for reuse; hasCommitted gates their content.60+ r.generation++
59 }61 }
60 62
61 // Bytes returns the prepared ANSI output. The returned bytes remain valid after63 // Bytes returns the prepared ANSI output. The returned bytes remain valid after
@@ -80,15 +82,24 @@ func (p *PreparedDraw) Commit() {
80 return82 return
81 }83 }
82 if p.generation != r.generation {84 if p.generation != r.generation {
83- // A later Prepare reused the scratch frame this draw's snapshot85+ // A later Prepare or Reset reused the scratch frame this draw's
84- // lives in, so it cannot be applied. Its bytes may nevertheless86+ // snapshot lives in, so it cannot be applied. Its bytes may
85- // have reached the terminal, which would then differ from the87+ // nevertheless have reached the terminal, which would then differ
86- // committed shadow in unknown ways: forget the shadow so the next88+ // from the committed shadow in unknown ways: forget the shadow and
87- // Prepare emits a full snapshot.89+ // invalidate every outstanding draw, so even a delta prepared
90+ // after this one cannot re-establish a shadow on commit and the
91+ // next Prepare emits a full snapshot.
88 r.hasCommitted = false92 r.hasCommitted = false
93+ r.generation++
94+ return
95+ }
96+ if !plan.Snapshot && !r.hasCommitted {
97+ // Unreachable for current draws: Prepare plans a snapshot whenever
98+ // no shadow exists, and every path that drops the shadow also
99+ // advances the generation. Keep the shadow dropped defensively.
89 return100 return
90 }101 }
91- if plan.Snapshot || !r.hasCommitted {102+ if plan.Snapshot {
92 // The snapshot lives in the renderer's scratch buffer; promote it103 // The snapshot lives in the renderer's scratch buffer; promote it
93 // and recycle the previous committed buffer as the next scratch.104 // and recycle the previous committed buffer as the next scratch.
94 r.committed, r.scratch = p.candidate.frame, r.committed105 r.committed, r.scratch = p.candidate.frame, r.committed
@@ -104,7 +115,8 @@ func (p *PreparedDraw) Commit() {
104 // Prepare plans and encodes a transactional draw. The renderer advances only115 // Prepare plans and encodes a transactional draw. The renderer advances only
105 // when the returned draw is committed. Keep at most one prepared draw116 // when the returned draw is committed. Keep at most one prepared draw
106 // outstanding; commit or discard it before calling Prepare again. A draw117 // outstanding; commit or discard it before calling Prepare again. A draw
107-// superseded by a later Prepare is discarded and its Commit does nothing.118+// superseded by a later Prepare is not applied: committing it forces the next
119+// Prepare to emit a full snapshot.
108 //120 //
109 // The renderer copies frame into reusable private storage, so the caller may121 // The renderer copies frame into reusable private storage, so the caller may
110 // keep mutating frame between draws.122 // keep mutating frame between draws.
M ansi/scroll.go +5 -8
@@ -76,11 +76,8 @@ func canApplyScrollAgainst(frame CellSource, scroll Damage, damage []Damage, com
7676 if !outsideScrollMatches(frame, scroll, damage, committed) {
7777 return false
7878 }
79- switch frame := frame.(type) {
80- case Frame:
81- return canApplyDenseScrollAgainst(frame, scroll, damage, committed)
82- case *Frame:
83- return canApplyDenseScrollAgainst(*frame, scroll, damage, committed)
79+ if dense, ok := asFrame(frame); ok {
80+ return canApplyDenseScrollAgainst(dense, scroll, damage, committed)
8481 }
8582 start, end, offset := scrollRetainedRows(scroll)
8683 for y := start; y < end; y++ {
@@ -101,9 +98,9 @@ func canApplyScrollAgainst(frame CellSource, scroll Damage, damage []Damage, com
10198 func canApplyDenseScrollAgainst(frame Frame, scroll Damage, damage []Damage, committed Frame) bool {
10299 start, end, offset := scrollRetainedRows(scroll)
103100 for y := start; y < end; y++ {
104- // Scrolls are full width, so a retained row that matches whole needs no
105- // per-cell damage lookups.
106- if scroll.X == 0 && scroll.Width == frame.Width && core.RowsEqualAt(committed, y+offset, frame, y) {
101+ // isSafeScroll guarantees full-width scrolls, so a retained row that
102+ // matches whole needs no per-cell damage lookups.
103+ if core.RowsEqualAt(committed, y+offset, frame, y) {
107104 continue
108105 }
109106 for x := range scroll.Width {
@@ -76,11 +76,8 @@ func canApplyScrollAgainst(frame CellSource, scroll Damage, damage []Damage, com
76 if !outsideScrollMatches(frame, scroll, damage, committed) {76 if !outsideScrollMatches(frame, scroll, damage, committed) {
77 return false77 return false
78 }78 }
79- switch frame := frame.(type) {79+ if dense, ok := asFrame(frame); ok {
80- case Frame:80+ return canApplyDenseScrollAgainst(dense, scroll, damage, committed)
81- return canApplyDenseScrollAgainst(frame, scroll, damage, committed)
82- case *Frame:
83- return canApplyDenseScrollAgainst(*frame, scroll, damage, committed)
84 }81 }
85 start, end, offset := scrollRetainedRows(scroll)82 start, end, offset := scrollRetainedRows(scroll)
86 for y := start; y < end; y++ {83 for y := start; y < end; y++ {
@@ -101,9 +98,9 @@ func canApplyScrollAgainst(frame CellSource, scroll Damage, damage []Damage, com
101 func canApplyDenseScrollAgainst(frame Frame, scroll Damage, damage []Damage, committed Frame) bool {98 func canApplyDenseScrollAgainst(frame Frame, scroll Damage, damage []Damage, committed Frame) bool {
102 start, end, offset := scrollRetainedRows(scroll)99 start, end, offset := scrollRetainedRows(scroll)
103 for y := start; y < end; y++ {100 for y := start; y < end; y++ {
104- // Scrolls are full width, so a retained row that matches whole needs no101+ // isSafeScroll guarantees full-width scrolls, so a retained row that
105- // per-cell damage lookups.102+ // matches whole needs no per-cell damage lookups.
106- if scroll.X == 0 && scroll.Width == frame.Width && core.RowsEqualAt(committed, y+offset, frame, y) {103+ if core.RowsEqualAt(committed, y+offset, frame, y) {
107 continue104 continue
108 }105 }
109 for x := range scroll.Width {106 for x := range scroll.Width {
M ansi/scroll_down_test.go +56 -0
@@ -78,6 +78,62 @@ func TestDownwardScrollMismatchFallsBack(t *testing.T) {
7878 }
7979 }
8080
81+// A stale commit followed by the current draw's commit, or a Reset between
82+// Prepare and Commit, must never leave a shadow that disagrees with the
83+// terminal: the next Prepare is a full snapshot.
84+func TestCommitAfterStaleCommitOrResetKeepsTerminalExact(t *testing.T) {
85+ for _, tc := range []string{"stale-then-current", "reset-between"} {
86+ t.Run(tc, func(t *testing.T) {
87+ frame := vt.NewFrame(10, 4)
88+ for y := range frame.Height {
89+ frame.FillRow(y, 0, frame.Width, vt.Cell{Rune: rune('a' + y), Style: vt.DefaultStyle()})
90+ }
91+ r := ansi.New(ansi.Capabilities{})
92+ terminal := vt.NewScreen(frame.Width, frame.Height)
93+ initial, err := r.Draw(frame, nil)
94+ if err != nil {
95+ t.Fatal(err)
96+ }
97+ terminal.Write(initial)
98+
99+ frame.Set(1, 1, vt.Cell{Rune: 'A', Style: vt.DefaultStyle()})
100+ a, err := r.Prepare(frame, []vt.Damage{{Kind: vt.DamageText, X: 1, Y: 1, Width: 1, Height: 1}}, false)
101+ if err != nil {
102+ t.Fatal(err)
103+ }
104+ terminal.Write(a.Bytes())
105+ // The caller reverts the cell before the next draw; only row 2 is damaged.
106+ frame.Set(1, 1, vt.Cell{Rune: 'b', Style: vt.DefaultStyle()})
107+ frame.Set(2, 2, vt.Cell{Rune: 'B', Style: vt.DefaultStyle()})
108+ if tc == "reset-between" {
109+ r.Reset()
110+ a.Commit()
111+ } else {
112+ b, err := r.Prepare(frame, []vt.Damage{{Kind: vt.DamageText, X: 2, Y: 2, Width: 1, Height: 1}}, false)
113+ if err != nil {
114+ t.Fatal(err)
115+ }
116+ terminal.Write(b.Bytes())
117+ a.Commit()
118+ b.Commit()
119+ }
120+ next, err := r.Prepare(frame, nil, false)
121+ if err != nil {
122+ t.Fatal(err)
123+ }
124+ terminal.Write(next.Bytes())
125+ next.Commit()
126+ for y := range frame.Height {
127+ for x := range frame.Width {
128+ if !frame.Cell(x, y).Equal(terminal.Cell(x, y)) {
129+ t.Fatalf("cell %d,%d = %+v, want %+v", x, y, terminal.Cell(x, y), frame.Cell(x, y))
130+ }
131+ }
132+ }
133+ })
134+ }
135+}
136+
81137 func TestStaleCommitForcesSnapshotAndReplaysCorrectly(t *testing.T) {
82138 for _, deliverB := range []bool{false, true} {
83139 frame := vt.NewFrame(10, 4)
@@ -78,6 +78,62 @@ func TestDownwardScrollMismatchFallsBack(t *testing.T) {
78 }78 }
79 }79 }
80 80
81+// A stale commit followed by the current draw's commit, or a Reset between
82+// Prepare and Commit, must never leave a shadow that disagrees with the
83+// terminal: the next Prepare is a full snapshot.
84+func TestCommitAfterStaleCommitOrResetKeepsTerminalExact(t *testing.T) {
85+ for _, tc := range []string{"stale-then-current", "reset-between"} {
86+ t.Run(tc, func(t *testing.T) {
87+ frame := vt.NewFrame(10, 4)
88+ for y := range frame.Height {
89+ frame.FillRow(y, 0, frame.Width, vt.Cell{Rune: rune('a' + y), Style: vt.DefaultStyle()})
90+ }
91+ r := ansi.New(ansi.Capabilities{})
92+ terminal := vt.NewScreen(frame.Width, frame.Height)
93+ initial, err := r.Draw(frame, nil)
94+ if err != nil {
95+ t.Fatal(err)
96+ }
97+ terminal.Write(initial)
98+
99+ frame.Set(1, 1, vt.Cell{Rune: 'A', Style: vt.DefaultStyle()})
100+ a, err := r.Prepare(frame, []vt.Damage{{Kind: vt.DamageText, X: 1, Y: 1, Width: 1, Height: 1}}, false)
101+ if err != nil {
102+ t.Fatal(err)
103+ }
104+ terminal.Write(a.Bytes())
105+ // The caller reverts the cell before the next draw; only row 2 is damaged.
106+ frame.Set(1, 1, vt.Cell{Rune: 'b', Style: vt.DefaultStyle()})
107+ frame.Set(2, 2, vt.Cell{Rune: 'B', Style: vt.DefaultStyle()})
108+ if tc == "reset-between" {
109+ r.Reset()
110+ a.Commit()
111+ } else {
112+ b, err := r.Prepare(frame, []vt.Damage{{Kind: vt.DamageText, X: 2, Y: 2, Width: 1, Height: 1}}, false)
113+ if err != nil {
114+ t.Fatal(err)
115+ }
116+ terminal.Write(b.Bytes())
117+ a.Commit()
118+ b.Commit()
119+ }
120+ next, err := r.Prepare(frame, nil, false)
121+ if err != nil {
122+ t.Fatal(err)
123+ }
124+ terminal.Write(next.Bytes())
125+ next.Commit()
126+ for y := range frame.Height {
127+ for x := range frame.Width {
128+ if !frame.Cell(x, y).Equal(terminal.Cell(x, y)) {
129+ t.Fatalf("cell %d,%d = %+v, want %+v", x, y, terminal.Cell(x, y), frame.Cell(x, y))
130+ }
131+ }
132+ }
133+ })
134+ }
135+}
136+
81 func TestStaleCommitForcesSnapshotAndReplaysCorrectly(t *testing.T) {137 func TestStaleCommitForcesSnapshotAndReplaysCorrectly(t *testing.T) {
82 for _, deliverB := range []bool{false, true} {138 for _, deliverB := range []bool{false, true} {
83 frame := vt.NewFrame(10, 4)139 frame := vt.NewFrame(10, 4)
M core/frame_copy.go +10 -12
@@ -57,17 +57,13 @@ func (f *Frame) CopyFrom(src Frame) {
5757 }
5858 }
5959
60-// RowsEqual reports whether logical row y holds semantically equal cells in a
61-// and b (the same comparison as Cell.Equal for every column). It compares
62-// compact stored cells directly and resolves page-local style and payload IDs
63-// only when they are not both the default, so it does not allocate and does not
64-// require the two frames to share ID tables. Frames of different width, an
65-// out-of-range row, or inconsistent storage compare unequal.
66-func RowsEqual(a, b Frame, y int) bool {
67- return RowsEqualAt(a, y, b, y)
68-}
69-
70-// RowsEqualAt is RowsEqual for logical row ya of a against logical row yb of b.
60+// RowsEqualAt reports whether logical row ya of a and logical row yb of b hold
61+// semantically equal cells (the same comparison as Cell.Equal for every
62+// column). It compares compact stored cells directly and resolves page-local
63+// style and payload IDs only when they are not both the default, so it does
64+// not allocate and does not require the two frames to share ID tables. Frames
65+// of different width, an out-of-range row, or inconsistent storage compare
66+// unequal.
7167 func RowsEqualAt(a Frame, ya int, b Frame, yb int) bool {
7268 if a.Width != b.Width || a.Width <= 0 || a.page == nil || b.page == nil ||
7369 ya < 0 || ya >= a.Height || yb < 0 || yb >= b.Height ||
@@ -99,7 +95,9 @@ func RowsEqualAt(a Frame, ya int, b Frame, yb int) bool {
9995 }
10096 }
10197 if ca.payloadID != 0 || cb.payloadID != 0 {
102- if ca.payloadID == 0 || cb.payloadID == 0 || a.payload(ca.payloadID) != b.payload(cb.payloadID) {
98+ if ca.payloadID == 0 || cb.payloadID == 0 ||
99+ int(ca.payloadID) > len(a.page.payloads) || int(cb.payloadID) > len(b.page.payloads) ||
100+ a.payload(ca.payloadID) != b.payload(cb.payloadID) {
103101 return false
104102 }
105103 }
@@ -57,17 +57,13 @@ func (f *Frame) CopyFrom(src Frame) {
57 }57 }
58 }58 }
59 59
60-// RowsEqual reports whether logical row y holds semantically equal cells in a60+// RowsEqualAt reports whether logical row ya of a and logical row yb of b hold
61-// and b (the same comparison as Cell.Equal for every column). It compares61+// semantically equal cells (the same comparison as Cell.Equal for every
62-// compact stored cells directly and resolves page-local style and payload IDs62+// column). It compares compact stored cells directly and resolves page-local
63-// only when they are not both the default, so it does not allocate and does not63+// style and payload IDs only when they are not both the default, so it does
64-// require the two frames to share ID tables. Frames of different width, an64+// not allocate and does not require the two frames to share ID tables. Frames
65-// out-of-range row, or inconsistent storage compare unequal.65+// of different width, an out-of-range row, or inconsistent storage compare
66-func RowsEqual(a, b Frame, y int) bool {66+// unequal.
67- return RowsEqualAt(a, y, b, y)
68-}
69-
70-// RowsEqualAt is RowsEqual for logical row ya of a against logical row yb of b.
71 func RowsEqualAt(a Frame, ya int, b Frame, yb int) bool {67 func RowsEqualAt(a Frame, ya int, b Frame, yb int) bool {
72 if a.Width != b.Width || a.Width <= 0 || a.page == nil || b.page == nil ||68 if a.Width != b.Width || a.Width <= 0 || a.page == nil || b.page == nil ||
73 ya < 0 || ya >= a.Height || yb < 0 || yb >= b.Height ||69 ya < 0 || ya >= a.Height || yb < 0 || yb >= b.Height ||
@@ -99,7 +95,9 @@ func RowsEqualAt(a Frame, ya int, b Frame, yb int) bool {
99 }95 }
100 }96 }
101 if ca.payloadID != 0 || cb.payloadID != 0 {97 if ca.payloadID != 0 || cb.payloadID != 0 {
102- if ca.payloadID == 0 || cb.payloadID == 0 || a.payload(ca.payloadID) != b.payload(cb.payloadID) {98+ if ca.payloadID == 0 || cb.payloadID == 0 ||
99+ int(ca.payloadID) > len(a.page.payloads) || int(cb.payloadID) > len(b.page.payloads) ||
100+ a.payload(ca.payloadID) != b.payload(cb.payloadID) {
103 return false101 return false
104 }102 }
105 }103 }
M core/frame_copy_test.go +19 -10
@@ -126,7 +126,7 @@ func TestRowsEqual(t *testing.T) {
126126 a := copyTestFrame(t, 10, 4, 'a')
127127 b := a.Clone()
128128 for y := range a.Height {
129- if !RowsEqual(a, b, y) {
129+ if !RowsEqualAt(a, y, b, y) {
130130 t.Fatalf("clone row %d differs", y)
131131 }
132132 }
@@ -141,11 +141,11 @@ func TestRowsEqual(t *testing.T) {
141141 }
142142 }
143143 for y := range a.Height {
144- if !RowsEqual(a, c, y) {
144+ if !RowsEqualAt(a, y, c, y) {
145145 t.Fatalf("semantically equal row %d reported different", y)
146146 }
147- if got, want := RowsEqual(a, c, y), reflect.DeepEqual(a.Row(y), c.Row(y)); got != want {
148- t.Fatalf("row %d: RowsEqual=%v DeepEqual=%v", y, got, want)
147+ if got, want := RowsEqualAt(a, y, c, y), reflect.DeepEqual(a.Row(y), c.Row(y)); got != want {
148+ t.Fatalf("row %d: RowsEqualAt=%v DeepEqual=%v", y, got, want)
149149 }
150150 }
151151
@@ -161,7 +161,7 @@ func TestRowsEqual(t *testing.T) {
161161 m.Set(3, 1, d)
162162 for y := range a.Height {
163163 want := y != 1
164- if got := RowsEqual(a, m, y); got != want {
164+ if got := RowsEqualAt(a, y, m, y); got != want {
165165 t.Fatalf("diff %d row %d: got %v want %v", i, y, got, want)
166166 }
167167 }
@@ -180,7 +180,7 @@ func TestRowsEqual(t *testing.T) {
180180 t.Fatal("test frame row 0 has no payload")
181181 }
182182 m.Set(px, 0, Cell{Rune: a.Cell(px, 0).Rune, Style: a.Cell(px, 0).Style})
183- if RowsEqual(a, m, 0) {
183+ if RowsEqualAt(a, 0, m, 0) {
184184 t.Fatal("payload removal not detected")
185185 }
186186
@@ -191,12 +191,12 @@ func TestRowsEqual(t *testing.T) {
191191 s2.ForegroundRGB = RGB{R: 9}
192192 e1.Set(0, 0, Cell{Rune: 'a', Style: s1})
193193 e2.Set(0, 0, Cell{Rune: 'a', Style: s2})
194- if !RowsEqual(e1, e2, 0) {
194+ if !RowsEqualAt(e1, 0, e2, 0) {
195195 t.Fatal("equivalent styles reported different")
196196 }
197197
198198 // Mismatched shape or range is unequal and never panics.
199- if RowsEqual(a, NewFrame(a.Width+1, a.Height), 0) || RowsEqual(a, b, -1) || RowsEqual(a, b, a.Height) || RowsEqual(Frame{}, Frame{}, 0) {
199+ if RowsEqualAt(a, 0, NewFrame(a.Width+1, a.Height), 0) || RowsEqualAt(a, -1, b, -1) || RowsEqualAt(a, a.Height, b, a.Height) || RowsEqualAt(Frame{}, 0, Frame{}, 0) {
200200 t.Fatal("invalid comparison reported equal")
201201 }
202202 }
@@ -204,8 +204,8 @@ func TestRowsEqual(t *testing.T) {
204204 func TestRowsEqualDoesNotAllocate(t *testing.T) {
205205 a := copyTestFrame(t, 80, 4, 'a')
206206 b := a.Clone()
207- if n := testing.AllocsPerRun(20, func() { RowsEqual(a, b, 2) }); n != 0 {
208- t.Fatalf("RowsEqual allocated %v times", n)
207+ if n := testing.AllocsPerRun(20, func() { RowsEqualAt(a, 2, b, 2) }); n != 0 {
208+ t.Fatalf("RowsEqualAt allocated %v times", n)
209209 }
210210 }
211211
@@ -297,3 +297,12 @@ func TestRowsEqualAt(t *testing.T) {
297297 t.Fatal("unequal or out-of-range rows reported equal")
298298 }
299299 }
300+
301+func TestRowsEqualAtRejectsCorruptPayloadIDs(t *testing.T) {
302+ a := copyTestFrame(t, 4, 1, 'a')
303+ b := a.Clone()
304+ b.page.cells[b.page.rows[0]].payloadID = uint32(len(b.page.payloads) + 5)
305+ if RowsEqualAt(a, 0, b, 0) || RowsEqualAt(b, 0, a, 0) {
306+ t.Fatal("corrupt payload ID reported equal")
307+ }
308+}
@@ -126,7 +126,7 @@ func TestRowsEqual(t *testing.T) {
126 a := copyTestFrame(t, 10, 4, 'a')126 a := copyTestFrame(t, 10, 4, 'a')
127 b := a.Clone()127 b := a.Clone()
128 for y := range a.Height {128 for y := range a.Height {
129- if !RowsEqual(a, b, y) {129+ if !RowsEqualAt(a, y, b, y) {
130 t.Fatalf("clone row %d differs", y)130 t.Fatalf("clone row %d differs", y)
131 }131 }
132 }132 }
@@ -141,11 +141,11 @@ func TestRowsEqual(t *testing.T) {
141 }141 }
142 }142 }
143 for y := range a.Height {143 for y := range a.Height {
144- if !RowsEqual(a, c, y) {144+ if !RowsEqualAt(a, y, c, y) {
145 t.Fatalf("semantically equal row %d reported different", y)145 t.Fatalf("semantically equal row %d reported different", y)
146 }146 }
147- if got, want := RowsEqual(a, c, y), reflect.DeepEqual(a.Row(y), c.Row(y)); got != want {147+ if got, want := RowsEqualAt(a, y, c, y), reflect.DeepEqual(a.Row(y), c.Row(y)); got != want {
148- t.Fatalf("row %d: RowsEqual=%v DeepEqual=%v", y, got, want)148+ t.Fatalf("row %d: RowsEqualAt=%v DeepEqual=%v", y, got, want)
149 }149 }
150 }150 }
151 151
@@ -161,7 +161,7 @@ func TestRowsEqual(t *testing.T) {
161 m.Set(3, 1, d)161 m.Set(3, 1, d)
162 for y := range a.Height {162 for y := range a.Height {
163 want := y != 1163 want := y != 1
164- if got := RowsEqual(a, m, y); got != want {164+ if got := RowsEqualAt(a, y, m, y); got != want {
165 t.Fatalf("diff %d row %d: got %v want %v", i, y, got, want)165 t.Fatalf("diff %d row %d: got %v want %v", i, y, got, want)
166 }166 }
167 }167 }
@@ -180,7 +180,7 @@ func TestRowsEqual(t *testing.T) {
180 t.Fatal("test frame row 0 has no payload")180 t.Fatal("test frame row 0 has no payload")
181 }181 }
182 m.Set(px, 0, Cell{Rune: a.Cell(px, 0).Rune, Style: a.Cell(px, 0).Style})182 m.Set(px, 0, Cell{Rune: a.Cell(px, 0).Rune, Style: a.Cell(px, 0).Style})
183- if RowsEqual(a, m, 0) {183+ if RowsEqualAt(a, 0, m, 0) {
184 t.Fatal("payload removal not detected")184 t.Fatal("payload removal not detected")
185 }185 }
186 186
@@ -191,12 +191,12 @@ func TestRowsEqual(t *testing.T) {
191 s2.ForegroundRGB = RGB{R: 9}191 s2.ForegroundRGB = RGB{R: 9}
192 e1.Set(0, 0, Cell{Rune: 'a', Style: s1})192 e1.Set(0, 0, Cell{Rune: 'a', Style: s1})
193 e2.Set(0, 0, Cell{Rune: 'a', Style: s2})193 e2.Set(0, 0, Cell{Rune: 'a', Style: s2})
194- if !RowsEqual(e1, e2, 0) {194+ if !RowsEqualAt(e1, 0, e2, 0) {
195 t.Fatal("equivalent styles reported different")195 t.Fatal("equivalent styles reported different")
196 }196 }
197 197
198 // Mismatched shape or range is unequal and never panics.198 // Mismatched shape or range is unequal and never panics.
199- if RowsEqual(a, NewFrame(a.Width+1, a.Height), 0) || RowsEqual(a, b, -1) || RowsEqual(a, b, a.Height) || RowsEqual(Frame{}, Frame{}, 0) {199+ if RowsEqualAt(a, 0, NewFrame(a.Width+1, a.Height), 0) || RowsEqualAt(a, -1, b, -1) || RowsEqualAt(a, a.Height, b, a.Height) || RowsEqualAt(Frame{}, 0, Frame{}, 0) {
200 t.Fatal("invalid comparison reported equal")200 t.Fatal("invalid comparison reported equal")
201 }201 }
202 }202 }
@@ -204,8 +204,8 @@ func TestRowsEqual(t *testing.T) {
204 func TestRowsEqualDoesNotAllocate(t *testing.T) {204 func TestRowsEqualDoesNotAllocate(t *testing.T) {
205 a := copyTestFrame(t, 80, 4, 'a')205 a := copyTestFrame(t, 80, 4, 'a')
206 b := a.Clone()206 b := a.Clone()
207- if n := testing.AllocsPerRun(20, func() { RowsEqual(a, b, 2) }); n != 0 {207+ if n := testing.AllocsPerRun(20, func() { RowsEqualAt(a, 2, b, 2) }); n != 0 {
208- t.Fatalf("RowsEqual allocated %v times", n)208+ t.Fatalf("RowsEqualAt allocated %v times", n)
209 }209 }
210 }210 }
211 211
@@ -297,3 +297,12 @@ func TestRowsEqualAt(t *testing.T) {
297 t.Fatal("unequal or out-of-range rows reported equal")297 t.Fatal("unequal or out-of-range rows reported equal")
298 }298 }
299 }299 }
300+
301+func TestRowsEqualAtRejectsCorruptPayloadIDs(t *testing.T) {
302+ a := copyTestFrame(t, 4, 1, 'a')
303+ b := a.Clone()
304+ b.page.cells[b.page.rows[0]].payloadID = uint32(len(b.page.payloads) + 5)
305+ if RowsEqualAt(a, 0, b, 0) || RowsEqualAt(b, 0, a, 0) {
306+ t.Fatal("corrupt payload ID reported equal")
307+ }
308+}
M docs/ownership.md +16 -0
@@ -26,6 +26,22 @@ an independent grid.
2626 Callbacks run synchronously, before `Screen.Write` returns. Avoid slow work in
2727 them. Copy response bytes during the callback if you need to retain them.
2828
29+## Borrowed and owned byte slices
30+
31+A few entry points skip a copy when the caller can promise exclusive ownership:
32+
33+- `kittygraphics.ParseAPCBorrowed` returns a command whose payload aliases the
34+ input. Keep the input unchanged while the command is in use.
35+ `Session.Process` never retains a command's payload, so the input may be
36+ reused once it returns.
37+- `graphics.Scene.AddAssetOwned` and `ReplaceAssetOwned` keep `Encoded` instead
38+ of copying it. Do not read or modify it afterwards. A slice with large spare
39+ capacity is still copied, so the scene retains only accounted bytes. On error
40+ the scene keeps nothing.
41+
42+The copying variants (`ParseAPC`, `AddAsset`, `ReplaceAsset`) remain the safe
43+default.
44+
2945 ## Styles
3046
3147 Use `DefaultStyle()` to leave foreground and background colors at the terminal's
@@ -26,6 +26,22 @@ an independent grid.
26 Callbacks run synchronously, before `Screen.Write` returns. Avoid slow work in26 Callbacks run synchronously, before `Screen.Write` returns. Avoid slow work in
27 them. Copy response bytes during the callback if you need to retain them.27 them. Copy response bytes during the callback if you need to retain them.
28 28
29+## Borrowed and owned byte slices
30+
31+A few entry points skip a copy when the caller can promise exclusive ownership:
32+
33+- `kittygraphics.ParseAPCBorrowed` returns a command whose payload aliases the
34+ input. Keep the input unchanged while the command is in use.
35+ `Session.Process` never retains a command's payload, so the input may be
36+ reused once it returns.
37+- `graphics.Scene.AddAssetOwned` and `ReplaceAssetOwned` keep `Encoded` instead
38+ of copying it. Do not read or modify it afterwards. A slice with large spare
39+ capacity is still copied, so the scene retains only accounted bytes. On error
40+ the scene keeps nothing.
41+
42+The copying variants (`ParseAPC`, `AddAsset`, `ReplaceAsset`) remain the safe
43+default.
44+
29 ## Styles45 ## Styles
30 46
31 Use `DefaultStyle()` to leave foreground and background colors at the terminal's47 Use `DefaultStyle()` to leave foreground and background colors at the terminal's
M docs/storage-optimization.md +1 -0
@@ -50,6 +50,7 @@ latency or claiming a precise speedup.
5050 | Geometry-bounded tail preallocation | Accepted | Large reproducible allocation reduction for small chunks; no ownership changes. |
5151 | Change default logical chunk rows | Rejected for now | Corrected throughput samples overlap. 256 rows uses fewer allocations/dictionaries than smaller chunks. |
5252 | Pool tail/page memory | Not justified yet | The immediate cause was excessive requested capacity. Sealed pages may outlive History through borrowed views, making recycling ownership-sensitive; pools can also retain cold memory. |
53+| Recycle the private mutable tail across seals | Accepted | Only History reads its tail: sealed chunks and views hold compact copies. Reusing that storage removed about 85% of the bytes allocated by `BenchmarkHistoryBuild10Kx120`. Retention is bounded: at most 128K cells (a default chunk up to 512 columns), and cleared cells, so payload strings are not pinned. Style scratch maps are dropped above 1,024 entries. Sealed pages are never pooled. |
5354 | mmap/decommit | Not justified | Go GC already releases dropped page references; no measured syscall/RSS benefit supports platform-specific backing, finalization and failure paths. |
5455 | SIMD | Not justified | The measured work is semantic cell writes and dictionary lookup, not a demonstrated bulk transform suited to SIMD. Native copy/clear remains the baseline. |
5556 | Fixed physical page alignment | Rejected | No measured benefit. Chunk rows are logical grouping, not an OS page-size commitment. |
@@ -50,6 +50,7 @@ latency or claiming a precise speedup.
50 | Geometry-bounded tail preallocation | Accepted | Large reproducible allocation reduction for small chunks; no ownership changes. |50 | Geometry-bounded tail preallocation | Accepted | Large reproducible allocation reduction for small chunks; no ownership changes. |
51 | Change default logical chunk rows | Rejected for now | Corrected throughput samples overlap. 256 rows uses fewer allocations/dictionaries than smaller chunks. |51 | Change default logical chunk rows | Rejected for now | Corrected throughput samples overlap. 256 rows uses fewer allocations/dictionaries than smaller chunks. |
52 | Pool tail/page memory | Not justified yet | The immediate cause was excessive requested capacity. Sealed pages may outlive History through borrowed views, making recycling ownership-sensitive; pools can also retain cold memory. |52 | Pool tail/page memory | Not justified yet | The immediate cause was excessive requested capacity. Sealed pages may outlive History through borrowed views, making recycling ownership-sensitive; pools can also retain cold memory. |
53+| Recycle the private mutable tail across seals | Accepted | Only History reads its tail: sealed chunks and views hold compact copies. Reusing that storage removed about 85% of the bytes allocated by `BenchmarkHistoryBuild10Kx120`. Retention is bounded: at most 128K cells (a default chunk up to 512 columns), and cleared cells, so payload strings are not pinned. Style scratch maps are dropped above 1,024 entries. Sealed pages are never pooled. |
53 | mmap/decommit | Not justified | Go GC already releases dropped page references; no measured syscall/RSS benefit supports platform-specific backing, finalization and failure paths. |54 | mmap/decommit | Not justified | Go GC already releases dropped page references; no measured syscall/RSS benefit supports platform-specific backing, finalization and failure paths. |
54 | SIMD | Not justified | The measured work is semantic cell writes and dictionary lookup, not a demonstrated bulk transform suited to SIMD. Native copy/clear remains the baseline. |55 | SIMD | Not justified | The measured work is semantic cell writes and dictionary lookup, not a demonstrated bulk transform suited to SIMD. Native copy/clear remains the baseline. |
55 | Fixed physical page alignment | Rejected | No measured benefit. Chunk rows are logical grouping, not an OS page-size commitment. |56 | Fixed physical page alignment | Rejected | No measured benefit. Chunk rows are logical grouping, not an OS page-size commitment. |
M graphics/scene.go +7 -2
@@ -436,8 +436,13 @@ func (s *Scene) prepareAsset(blob AssetBlob, state *sceneState, copyEncoded bool
436436 if !within(state.usage.DecodedPixels, pixels, s.limits.MaxDecodedPixels) {
437437 return assetRecord{}, fmt.Errorf("add asset: %w", ErrDecodedPixelBudget)
438438 }
439- if copyEncoded {
440- data = append([]byte(nil), data...)
439+ // Budgets count len(data). An owned slice with spare capacity would keep
440+ // unaccounted memory alive (for example base64 input padded with CR/LF
441+ // or a zlib read buffer), so it is trimmed by copying.
442+ if copyEncoded || cap(data)-len(data) > len(data)/8 {
443+ exact := make([]byte, len(data))
444+ copy(exact, data)
445+ data = exact
441446 }
442447 return assetRecord{encoded: data, format: blob.Format, width: blob.Width, height: blob.Height, pixels: pixels}, nil
443448 }
@@ -436,8 +436,13 @@ func (s *Scene) prepareAsset(blob AssetBlob, state *sceneState, copyEncoded bool
436 if !within(state.usage.DecodedPixels, pixels, s.limits.MaxDecodedPixels) {436 if !within(state.usage.DecodedPixels, pixels, s.limits.MaxDecodedPixels) {
437 return assetRecord{}, fmt.Errorf("add asset: %w", ErrDecodedPixelBudget)437 return assetRecord{}, fmt.Errorf("add asset: %w", ErrDecodedPixelBudget)
438 }438 }
439- if copyEncoded {439+ // Budgets count len(data). An owned slice with spare capacity would keep
440- data = append([]byte(nil), data...)440+ // unaccounted memory alive (for example base64 input padded with CR/LF
441+ // or a zlib read buffer), so it is trimmed by copying.
442+ if copyEncoded || cap(data)-len(data) > len(data)/8 {
443+ exact := make([]byte, len(data))
444+ copy(exact, data)
445+ data = exact
441 }446 }
442 return assetRecord{encoded: data, format: blob.Format, width: blob.Width, height: blob.Height, pixels: pixels}, nil447 return assetRecord{encoded: data, format: blob.Format, width: blob.Width, height: blob.Height, pixels: pixels}, nil
443 }448 }
M graphics/scene_test.go +35 -0
@@ -28,6 +28,41 @@ func TestRectOperationsRejectOverflow(t *testing.T) {
2828 }
2929 }
3030
31+// Owned assets keep only accounted memory: a slice with large spare capacity
32+// is trimmed, a tight one is kept as is, and a rejected blob is not retained.
33+func TestOwnedAssetsRetainOnlyAccountedBytes(t *testing.T) {
34+ scene := NewScene(Limits{MaxEncodedBytes: 1 << 20, MaxDecodedPixels: 1 << 20})
35+ loose := make([]byte, 4, 1<<16)
36+ id, err := scene.AddAssetOwned(testAsset(t, loose, 1, 1))
37+ if err != nil {
38+ t.Fatal(err)
39+ }
40+ if got := scene.state.assets[id].encoded; cap(got) != len(got) || &got[0] == &loose[0] {
41+ t.Fatalf("loose owned slice retained with cap %d for len %d", cap(got), len(got))
42+ }
43+ tight := []byte{1, 2, 3, 4}
44+ id, err = scene.ReplaceAssetOwned(id, testAsset(t, tight, 1, 1))
45+ if err != nil {
46+ t.Fatal(err)
47+ }
48+ if got := scene.state.assets[id].encoded; &got[0] != &tight[0] {
49+ t.Fatal("tight owned slice was copied")
50+ }
51+ before := scene.Snapshot()
52+ rejected := make([]byte, 2<<20)
53+ if _, err := scene.AddAssetOwned(testAsset(t, rejected, 1, 1)); !errors.Is(err, ErrEncodedBudget) {
54+ t.Fatalf("over-budget owned asset error = %v", err)
55+ }
56+ for _, asset := range scene.state.assets {
57+ if len(asset.encoded) > 0 && &asset.encoded[0] == &rejected[0] {
58+ t.Fatal("rejected owned blob retained")
59+ }
60+ }
61+ if scene.Snapshot().Usage() != before.Usage() {
62+ t.Fatal("rejected owned blob changed usage")
63+ }
64+}
65+
3166 func TestAssetBlobOwnershipAndSnapshotLifecycle(t *testing.T) {
3267 scene := NewScene(Limits{MaxEncodedBytes: 32, MaxDecodedPixels: 64})
3368 encoded := []byte{1, 2, 3}
@@ -28,6 +28,41 @@ func TestRectOperationsRejectOverflow(t *testing.T) {
28 }28 }
29 }29 }
30 30
31+// Owned assets keep only accounted memory: a slice with large spare capacity
32+// is trimmed, a tight one is kept as is, and a rejected blob is not retained.
33+func TestOwnedAssetsRetainOnlyAccountedBytes(t *testing.T) {
34+ scene := NewScene(Limits{MaxEncodedBytes: 1 << 20, MaxDecodedPixels: 1 << 20})
35+ loose := make([]byte, 4, 1<<16)
36+ id, err := scene.AddAssetOwned(testAsset(t, loose, 1, 1))
37+ if err != nil {
38+ t.Fatal(err)
39+ }
40+ if got := scene.state.assets[id].encoded; cap(got) != len(got) || &got[0] == &loose[0] {
41+ t.Fatalf("loose owned slice retained with cap %d for len %d", cap(got), len(got))
42+ }
43+ tight := []byte{1, 2, 3, 4}
44+ id, err = scene.ReplaceAssetOwned(id, testAsset(t, tight, 1, 1))
45+ if err != nil {
46+ t.Fatal(err)
47+ }
48+ if got := scene.state.assets[id].encoded; &got[0] != &tight[0] {
49+ t.Fatal("tight owned slice was copied")
50+ }
51+ before := scene.Snapshot()
52+ rejected := make([]byte, 2<<20)
53+ if _, err := scene.AddAssetOwned(testAsset(t, rejected, 1, 1)); !errors.Is(err, ErrEncodedBudget) {
54+ t.Fatalf("over-budget owned asset error = %v", err)
55+ }
56+ for _, asset := range scene.state.assets {
57+ if len(asset.encoded) > 0 && &asset.encoded[0] == &rejected[0] {
58+ t.Fatal("rejected owned blob retained")
59+ }
60+ }
61+ if scene.Snapshot().Usage() != before.Usage() {
62+ t.Fatal("rejected owned blob changed usage")
63+ }
64+}
65+
31 func TestAssetBlobOwnershipAndSnapshotLifecycle(t *testing.T) {66 func TestAssetBlobOwnershipAndSnapshotLifecycle(t *testing.T) {
32 scene := NewScene(Limits{MaxEncodedBytes: 32, MaxDecodedPixels: 64})67 scene := NewScene(Limits{MaxEncodedBytes: 32, MaxDecodedPixels: 64})
33 encoded := []byte{1, 2, 3}68 encoded := []byte{1, 2, 3}
M history.go +6 -1
@@ -17,6 +17,11 @@ var errInvalidHistoryRowID = errors.New("invalid history row ID")
1717
1818 const maxTailPreallocCells = 32 * 1024
1919
20+// maxRetainedTailCells bounds tail storage recycled across seals. It covers a
21+// full default chunk of terminals up to 512 columns, so wide terminals reuse
22+// their tail too, while rare very wide rows are still released.
23+const maxRetainedTailCells = 4 * maxTailPreallocCells
24+
2025 // History stores terminal rows in immutable chunks. It is intended to be
2126 // mutated by the owner of a Screen; views are safe to retain after later
2227 // appends.
@@ -557,7 +562,7 @@ func (h *History) sealTail() {
557562 // storage (wide rows) is released as before.
558563 clear(h.tail)
559564 h.tail = h.tail[:0]
560- if cap(h.tailCells) > maxTailPreallocCells {
565+ if cap(h.tailCells) > maxRetainedTailCells {
561566 h.tailCells = nil
562567 } else {
563568 clear(h.tailCells)
@@ -17,6 +17,11 @@ var errInvalidHistoryRowID = errors.New("invalid history row ID")
17 17
18 const maxTailPreallocCells = 32 * 102418 const maxTailPreallocCells = 32 * 1024
19 19
20+// maxRetainedTailCells bounds tail storage recycled across seals. It covers a
21+// full default chunk of terminals up to 512 columns, so wide terminals reuse
22+// their tail too, while rare very wide rows are still released.
23+const maxRetainedTailCells = 4 * maxTailPreallocCells
24+
20 // History stores terminal rows in immutable chunks. It is intended to be25 // History stores terminal rows in immutable chunks. It is intended to be
21 // mutated by the owner of a Screen; views are safe to retain after later26 // mutated by the owner of a Screen; views are safe to retain after later
22 // appends.27 // appends.
@@ -557,7 +562,7 @@ func (h *History) sealTail() {
557 // storage (wide rows) is released as before.562 // storage (wide rows) is released as before.
558 clear(h.tail)563 clear(h.tail)
559 h.tail = h.tail[:0]564 h.tail = h.tail[:0]
560- if cap(h.tailCells) > maxTailPreallocCells {565+ if cap(h.tailCells) > maxRetainedTailCells {
561 h.tailCells = nil566 h.tailCells = nil
562 } else {567 } else {
563 clear(h.tailCells)568 clear(h.tailCells)
M history_tail_reuse_test.go +16 -0
@@ -93,6 +93,22 @@ func TestHistoryTailStorageIsRecycledAcrossSeals(t *testing.T) {
9393 require.NoError(t, h.chunks[len(h.chunks)-1].CheckInvariants())
9494 }
9595
96+// Default chunks of wide terminals (256 rows × 200 columns) must recycle their
97+// tail storage too.
98+func TestHistoryTailStorageIsRecycledForWideTerminals(t *testing.T) {
99+ const width = 200
100+ h := NewHistory(HistoryConfig{MaxRows: 4096, MaxBytes: 1 << 30})
101+ row := make([]renderer.Cell, width)
102+ for i := range row {
103+ row[i] = renderer.Cell{Rune: 'w', Style: renderer.DefaultStyle()}
104+ }
105+ for range 256 {
106+ require.NoError(t, h.Append(row, LineBound{End: width}))
107+ }
108+ require.Empty(t, h.tail)
109+ require.GreaterOrEqual(t, cap(h.tailCells), 256*width, "seal released wide-terminal tail storage")
110+}
111+
96112 // Eviction from a partial tail must not leave the evicted rows' payload
97113 // strings pinned in the recycled backing array's prefix.
98114 func TestHistoryTailEvictionClearsEvictedPrefix(t *testing.T) {
@@ -93,6 +93,22 @@ func TestHistoryTailStorageIsRecycledAcrossSeals(t *testing.T) {
93 require.NoError(t, h.chunks[len(h.chunks)-1].CheckInvariants())93 require.NoError(t, h.chunks[len(h.chunks)-1].CheckInvariants())
94 }94 }
95 95
96+// Default chunks of wide terminals (256 rows × 200 columns) must recycle their
97+// tail storage too.
98+func TestHistoryTailStorageIsRecycledForWideTerminals(t *testing.T) {
99+ const width = 200
100+ h := NewHistory(HistoryConfig{MaxRows: 4096, MaxBytes: 1 << 30})
101+ row := make([]renderer.Cell, width)
102+ for i := range row {
103+ row[i] = renderer.Cell{Rune: 'w', Style: renderer.DefaultStyle()}
104+ }
105+ for range 256 {
106+ require.NoError(t, h.Append(row, LineBound{End: width}))
107+ }
108+ require.Empty(t, h.tail)
109+ require.GreaterOrEqual(t, cap(h.tailCells), 256*width, "seal released wide-terminal tail storage")
110+}
111+
96 // Eviction from a partial tail must not leave the evicted rows' payload112 // Eviction from a partial tail must not leave the evicted rows' payload
97 // strings pinned in the recycled backing array's prefix.113 // strings pinned in the recycled backing array's prefix.
98 func TestHistoryTailEvictionClearsEvictedPrefix(t *testing.T) {114 func TestHistoryTailEvictionClearsEvictedPrefix(t *testing.T) {
M html/encode.go +4 -10
@@ -1,9 +1,7 @@
11 package html
22
33 import (
4- "encoding/json"
54 "fmt"
6- "reflect"
75 "strconv"
86 "unicode/utf8"
97 )
@@ -157,11 +155,7 @@ func appendColorJSON(dst []byte, color Color) ([]byte, error) {
157155 dst = strconv.AppendUint(dst, uint64(color.RGB.B), 10)
158156 return append(dst, "}}"...), nil
159157 default:
160- // Same error value encoding/json produced via Color.MarshalJSON.
161- return nil, &json.MarshalerError{
162- Type: reflect.TypeFor[*Color](),
163- Err: fmt.Errorf("html: invalid color kind %d", color.Kind),
164- }
158+ return nil, fmt.Errorf("html: invalid color kind %d", color.Kind)
165159 }
166160 }
167161
@@ -169,8 +163,8 @@ const hexDigits = "0123456789abcdef"
169163
170164 // appendJSONString appends s as a JSON string using encoding/json's default
171165 // escaping: quotes, backslashes, control characters, <, >, & and U+2028/2029
172-// are escaped, and each invalid UTF-8 byte becomes U+FFFD written as the
173-// literal character, byte-identical to encoding/json on this toolchain.
166+// are escaped. Cell text is always valid UTF-8; an invalid byte, should one
167+// appear, is replaced by U+FFFD so the output stays valid JSON.
174168 func appendJSONString(dst []byte, s string) []byte {
175169 dst = append(dst, '"')
176170 start := 0
@@ -226,7 +220,7 @@ func appendJSONString(dst []byte, s string) []byte {
226220 // estimateUpdateJSONSize returns a capacity hint close to the encoded size so
227221 // the output buffer normally grows zero times.
228222 func estimateUpdateJSONSize(update Update) int {
229- size := 256 + 160*len(update.Styles)
223+ size := 256 + 256*len(update.Styles)
230224 for i := range update.Rows {
231225 size += 32 + 48*len(update.Rows[i].Cells)
232226 }
@@ -1,9 +1,7 @@
1 package html1 package html
2 2
3 import (3 import (
4- "encoding/json"
5 "fmt"4 "fmt"
6- "reflect"
7 "strconv"5 "strconv"
8 "unicode/utf8"6 "unicode/utf8"
9 )7 )
@@ -157,11 +155,7 @@ func appendColorJSON(dst []byte, color Color) ([]byte, error) {
157 dst = strconv.AppendUint(dst, uint64(color.RGB.B), 10)155 dst = strconv.AppendUint(dst, uint64(color.RGB.B), 10)
158 return append(dst, "}}"...), nil156 return append(dst, "}}"...), nil
159 default:157 default:
160- // Same error value encoding/json produced via Color.MarshalJSON.158+ return nil, fmt.Errorf("html: invalid color kind %d", color.Kind)
161- return nil, &json.MarshalerError{
162- Type: reflect.TypeFor[*Color](),
163- Err: fmt.Errorf("html: invalid color kind %d", color.Kind),
164- }
165 }159 }
166 }160 }
167 161
@@ -169,8 +163,8 @@ const hexDigits = "0123456789abcdef"
169 163
170 // appendJSONString appends s as a JSON string using encoding/json's default164 // appendJSONString appends s as a JSON string using encoding/json's default
171 // escaping: quotes, backslashes, control characters, <, >, & and U+2028/2029165 // escaping: quotes, backslashes, control characters, <, >, & and U+2028/2029
172-// are escaped, and each invalid UTF-8 byte becomes U+FFFD written as the166+// are escaped. Cell text is always valid UTF-8; an invalid byte, should one
173-// literal character, byte-identical to encoding/json on this toolchain.167+// appear, is replaced by U+FFFD so the output stays valid JSON.
174 func appendJSONString(dst []byte, s string) []byte {168 func appendJSONString(dst []byte, s string) []byte {
175 dst = append(dst, '"')169 dst = append(dst, '"')
176 start := 0170 start := 0
@@ -226,7 +220,7 @@ func appendJSONString(dst []byte, s string) []byte {
226 // estimateUpdateJSONSize returns a capacity hint close to the encoded size so220 // estimateUpdateJSONSize returns a capacity hint close to the encoded size so
227 // the output buffer normally grows zero times.221 // the output buffer normally grows zero times.
228 func estimateUpdateJSONSize(update Update) int {222 func estimateUpdateJSONSize(update Update) int {
229- size := 256 + 160*len(update.Styles)223+ size := 256 + 256*len(update.Styles)
230 for i := range update.Rows {224 for i := range update.Rows {
231 size += 32 + 48*len(update.Rows[i].Cells)225 size += 32 + 48*len(update.Rows[i].Cells)
232 }226 }
M html/encode_test.go +24 -8
@@ -5,6 +5,7 @@ import (
55 "math/rand"
66 "reflect"
77 "testing"
8+ "unicode/utf8"
89
910 "github.com/bnema/vev-vt/core"
1011 "github.com/stretchr/testify/require"
@@ -25,14 +26,32 @@ func TestAppendJSONStringMatchesEncodingJSON(t *testing.T) {
2526 }
2627 }
2728
28-// Invalid UTF-8 never reaches the encoder (cells are validated), but the
29-// escaping must still match encoding/json byte for byte.
30-func TestAppendJSONStringInvalidUTF8MatchesEncodingJSON(t *testing.T) {
29+// Invalid UTF-8 never reaches the encoder (cells are validated). Should it,
30+// the output must stay valid JSON decoding to the same text encoding/json
31+// would produce, whatever escaping style the toolchain's encoder uses.
32+func TestAppendJSONStringInvalidUTF8StaysValidJSON(t *testing.T) {
3133 for _, text := range []string{"\xff", "a\xc3", "\xed\xa0\x80", "\xe2\x80", "ok\xf0\x9f"} {
3234 want, err := json.Marshal(text)
3335 require.NoError(t, err)
34- require.Equal(t, string(want), string(appendJSONString(nil, text)), "%q", text)
36+ var wantText, gotText string
37+ require.NoError(t, json.Unmarshal(want, &wantText))
38+ require.NoError(t, json.Unmarshal(appendJSONString(nil, text), &gotText), "%q", text)
39+ require.Equal(t, wantText, gotText, "%q", text)
40+ }
41+}
42+
43+func FuzzAppendJSONString(f *testing.F) {
44+ for _, seed := range []string{"", "a<b>&c", "\u2028\u2029", "界😀", "\x00\x1f\x7f"} {
45+ f.Add(seed)
3546 }
47+ f.Fuzz(func(t *testing.T, text string) {
48+ if !utf8.ValidString(text) {
49+ t.Skip("cell text is always valid UTF-8")
50+ }
51+ want, err := json.Marshal(text)
52+ require.NoError(t, err)
53+ require.Equal(t, string(want), string(appendJSONString(nil, text)))
54+ })
3655 }
3756
3857 func TestAsciiTextIndexesEveryByte(t *testing.T) {
@@ -100,9 +119,7 @@ func TestAppendUpdateJSONMatchesEncodingJSON(t *testing.T) {
100119 func TestAppendUpdateJSONRejectsInvalidColorKind(t *testing.T) {
101120 update := Update{Styles: []Style{{Foreground: Color{Kind: 9}}}}
102121 _, err := appendUpdateJSON(nil, update)
103- _, want := json.Marshal(update)
104- require.Error(t, want)
105- require.EqualError(t, err, want.Error())
122+ require.ErrorContains(t, err, "invalid color kind 9")
106123 }
107124
108125 func TestPreparedJSONMatchesEncodingJSONOfUpdate(t *testing.T) {
@@ -126,7 +143,6 @@ func TestPreparedJSONMatchesEncodingJSONOfUpdate(t *testing.T) {
126143 want, err := json.Marshal(prepared.tx.update)
127144 require.NoError(t, err)
128145 require.Equal(t, string(want), string(prepared.JSON()))
129- require.Contains(t, string(prepared.JSON()), "😀")
130146 }
131147
132148 // fillAll sets every field reachable from v to a distinctive non-zero value
@@ -5,6 +5,7 @@ import (
5 "math/rand"5 "math/rand"
6 "reflect"6 "reflect"
7 "testing"7 "testing"
8+ "unicode/utf8"
8 9
9 "github.com/bnema/vev-vt/core"10 "github.com/bnema/vev-vt/core"
10 "github.com/stretchr/testify/require"11 "github.com/stretchr/testify/require"
@@ -25,14 +26,32 @@ func TestAppendJSONStringMatchesEncodingJSON(t *testing.T) {
25 }26 }
26 }27 }
27 28
28-// Invalid UTF-8 never reaches the encoder (cells are validated), but the29+// Invalid UTF-8 never reaches the encoder (cells are validated). Should it,
29-// escaping must still match encoding/json byte for byte.30+// the output must stay valid JSON decoding to the same text encoding/json
30-func TestAppendJSONStringInvalidUTF8MatchesEncodingJSON(t *testing.T) {31+// would produce, whatever escaping style the toolchain's encoder uses.
32+func TestAppendJSONStringInvalidUTF8StaysValidJSON(t *testing.T) {
31 for _, text := range []string{"\xff", "a\xc3", "\xed\xa0\x80", "\xe2\x80", "ok\xf0\x9f"} {33 for _, text := range []string{"\xff", "a\xc3", "\xed\xa0\x80", "\xe2\x80", "ok\xf0\x9f"} {
32 want, err := json.Marshal(text)34 want, err := json.Marshal(text)
33 require.NoError(t, err)35 require.NoError(t, err)
34- require.Equal(t, string(want), string(appendJSONString(nil, text)), "%q", text)36+ var wantText, gotText string
37+ require.NoError(t, json.Unmarshal(want, &wantText))
38+ require.NoError(t, json.Unmarshal(appendJSONString(nil, text), &gotText), "%q", text)
39+ require.Equal(t, wantText, gotText, "%q", text)
40+ }
41+}
42+
43+func FuzzAppendJSONString(f *testing.F) {
44+ for _, seed := range []string{"", "a<b>&c", "\u2028\u2029", "界😀", "\x00\x1f\x7f"} {
45+ f.Add(seed)
35 }46 }
47+ f.Fuzz(func(t *testing.T, text string) {
48+ if !utf8.ValidString(text) {
49+ t.Skip("cell text is always valid UTF-8")
50+ }
51+ want, err := json.Marshal(text)
52+ require.NoError(t, err)
53+ require.Equal(t, string(want), string(appendJSONString(nil, text)))
54+ })
36 }55 }
37 56
38 func TestAsciiTextIndexesEveryByte(t *testing.T) {57 func TestAsciiTextIndexesEveryByte(t *testing.T) {
@@ -100,9 +119,7 @@ func TestAppendUpdateJSONMatchesEncodingJSON(t *testing.T) {
100 func TestAppendUpdateJSONRejectsInvalidColorKind(t *testing.T) {119 func TestAppendUpdateJSONRejectsInvalidColorKind(t *testing.T) {
101 update := Update{Styles: []Style{{Foreground: Color{Kind: 9}}}}120 update := Update{Styles: []Style{{Foreground: Color{Kind: 9}}}}
102 _, err := appendUpdateJSON(nil, update)121 _, err := appendUpdateJSON(nil, update)
103- _, want := json.Marshal(update)122+ require.ErrorContains(t, err, "invalid color kind 9")
104- require.Error(t, want)
105- require.EqualError(t, err, want.Error())
106 }123 }
107 124
108 func TestPreparedJSONMatchesEncodingJSONOfUpdate(t *testing.T) {125 func TestPreparedJSONMatchesEncodingJSONOfUpdate(t *testing.T) {
@@ -126,7 +143,6 @@ func TestPreparedJSONMatchesEncodingJSONOfUpdate(t *testing.T) {
126 want, err := json.Marshal(prepared.tx.update)143 want, err := json.Marshal(prepared.tx.update)
127 require.NoError(t, err)144 require.NoError(t, err)
128 require.Equal(t, string(want), string(prepared.JSON()))145 require.Equal(t, string(want), string(prepared.JSON()))
129- require.Contains(t, string(prepared.JSON()), "😀")
130 }146 }
131 147
132 // fillAll sets every field reachable from v to a distinctive non-zero value148 // fillAll sets every field reachable from v to a distinctive non-zero value
M html/renderer.go +3 -1
@@ -287,7 +287,9 @@ func (r *Renderer) buildUpdate(frame core.Frame, scratch []core.Cell, snapshot b
287287 // the exact encoded size. The previous conservative estimate could reject
288288 // compact updates well below the configured limit.
289289 func encodeBoundedUpdate(update Update, limit int) ([]byte, error) {
290- encoded, err := appendUpdateJSON(make([]byte, 0, estimateUpdateJSONSize(update)), update)
290+ // The hint never exceeds limit+1, so an oversized update cannot reserve
291+ // its full estimate before the limit rejects it.
292+ encoded, err := appendUpdateJSON(make([]byte, 0, min(estimateUpdateJSONSize(update), limit+1)), update)
291293 if err != nil {
292294 return nil, fmt.Errorf("html: encode update: %w", err)
293295 }
@@ -287,7 +287,9 @@ func (r *Renderer) buildUpdate(frame core.Frame, scratch []core.Cell, snapshot b
287 // the exact encoded size. The previous conservative estimate could reject287 // the exact encoded size. The previous conservative estimate could reject
288 // compact updates well below the configured limit.288 // compact updates well below the configured limit.
289 func encodeBoundedUpdate(update Update, limit int) ([]byte, error) {289 func encodeBoundedUpdate(update Update, limit int) ([]byte, error) {
290- encoded, err := appendUpdateJSON(make([]byte, 0, estimateUpdateJSONSize(update)), update)290+ // The hint never exceeds limit+1, so an oversized update cannot reserve
291+ // its full estimate before the limit rejects it.
292+ encoded, err := appendUpdateJSON(make([]byte, 0, min(estimateUpdateJSONSize(update), limit+1)), update)
291 if err != nil {293 if err != nil {
292 return nil, fmt.Errorf("html: encode update: %w", err)294 return nil, fmt.Errorf("html: encode update: %w", err)
293 }295 }
M html/renderer_test.go +0 -15
@@ -287,21 +287,6 @@ func TestAbortThenPrepareKeepsCommittedShadow(t *testing.T) {
287287 require.Empty(t, steady.Update().Rows)
288288 }
289289
290-func TestPrepareDoesNotAliasCallerFrame(t *testing.T) {
291- frame := core.NewFrame(2, 1)
292- renderer, err := New(Options{})
293- require.NoError(t, err)
294- prepared, err := renderer.Prepare(frame, nil, false, Cursor{})
295- require.NoError(t, err)
296- require.NoError(t, prepared.Commit())
297-
298- // Mutating the caller frame after Commit must be seen as a change.
299- frame.Set(0, 0, core.Cell{Rune: 'Q', Style: core.DefaultStyle()})
300- next, err := renderer.Prepare(frame, nil, false, Cursor{})
301- require.NoError(t, err)
302- require.Equal(t, []int{0}, rowIndexes(next.Update()))
303-}
304-
305290 func rowIndexes(update Update) []int {
306291 rows := make([]int, 0, len(update.Rows))
307292 for _, row := range update.Rows {
@@ -287,21 +287,6 @@ func TestAbortThenPrepareKeepsCommittedShadow(t *testing.T) {
287 require.Empty(t, steady.Update().Rows)287 require.Empty(t, steady.Update().Rows)
288 }288 }
289 289
290-func TestPrepareDoesNotAliasCallerFrame(t *testing.T) {
291- frame := core.NewFrame(2, 1)
292- renderer, err := New(Options{})
293- require.NoError(t, err)
294- prepared, err := renderer.Prepare(frame, nil, false, Cursor{})
295- require.NoError(t, err)
296- require.NoError(t, prepared.Commit())
297-
298- // Mutating the caller frame after Commit must be seen as a change.
299- frame.Set(0, 0, core.Cell{Rune: 'Q', Style: core.DefaultStyle()})
300- next, err := renderer.Prepare(frame, nil, false, Cursor{})
301- require.NoError(t, err)
302- require.Equal(t, []int{0}, rowIndexes(next.Update()))
303-}
304-
305 func rowIndexes(update Update) []int {290 func rowIndexes(update Update) []int {
306 rows := make([]int, 0, len(update.Rows))291 rows := make([]int, 0, len(update.Rows))
307 for _, row := range update.Rows {292 for _, row := range update.Rows {
A oracle_norace_test.go +5 -0
@@ -0,0 +1,5 @@
1+//go:build !race
2+
3+package vt_test
4+
5+const raceEnabled = false
@@ -0,0 +1,5 @@
1+//go:build !race
2+
3+package vt_test
4+
5+const raceEnabled = false
A oracle_race_test.go +5 -0
@@ -0,0 +1,5 @@
1+//go:build race
2+
3+package vt_test
4+
5+const raceEnabled = true
@@ -0,0 +1,5 @@
1+//go:build race
2+
3+package vt_test
4+
5+const raceEnabled = true
M oracle_test.go +111 -43
@@ -78,21 +78,47 @@ type oracleRun struct {
7878 // mirror reproduces the vev daemon consumer: one core.Frame reused and
7979 // mutated in place between draws, so renderer shadows must not alias it.
8080 mirror core.Frame
81- h hash.Hash
81+ // hashes holds one digest per observable concern, so an intentional
82+ // change to one layer (for example ANSI bytes) leaves the others'
83+ // golden columns untouched and auditable.
84+ hashes map[string]hash.Hash
8285 dump *bufio.Writer
8386 events []string
8487 }
8588
86-func (o *oracleRun) emit(format string, args ...any) {
89+// oracleConcerns are the golden columns, in output order. "input" covers the
90+// generated workload and VT callbacks; the others cover one layer each.
91+var oracleConcerns = []string{"input", "vt", "graphics", "history", "ansi", "ansi256", "html"}
92+
93+func (o *oracleRun) emit(concern, format string, args ...any) {
8794 line := fmt.Sprintf(format, args...)
88- o.h.Write([]byte(line))
89- o.h.Write([]byte{'\n'})
95+ h := o.hashes[concern]
96+ if h == nil {
97+ o.t.Fatalf("unknown oracle concern %q", concern)
98+ }
99+ h.Write([]byte(line))
100+ h.Write([]byte{'\n'})
90101 if o.dump != nil {
102+ o.dump.WriteString(concern)
103+ o.dump.WriteString(": ")
91104 o.dump.WriteString(line)
92105 o.dump.WriteByte('\n')
93106 }
94107 }
95108
109+func (o *oracleRun) digest() string {
110+ var b strings.Builder
111+ for i, concern := range oracleConcerns {
112+ if i > 0 {
113+ b.WriteByte(' ')
114+ }
115+ b.WriteString(concern)
116+ b.WriteByte('=')
117+ b.WriteString(hex.EncodeToString(o.hashes[concern].Sum(nil))[:12])
118+ }
119+ return b.String()
120+}
121+
96122 func formatCell(c core.Cell) string {
97123 return fmt.Sprintf("%q|%+v|%q|%q|%t", c.Rune, c.Style, c.Payload.Grapheme(), c.Payload.Hyperlink(), c.Continuation)
98124 }
@@ -284,41 +310,41 @@ func (o *oracleRun) maybeResize(step int) {
284310 return
285311 }
286312 cols, rows := 8+o.r.IntN(110), 3+o.r.IntN(40)
287- o.emit("step %d resize %dx%d", step, cols, rows)
313+ o.emit("input", "step %d resize %dx%d", step, cols, rows)
288314 o.screen.Resize(cols, rows)
289315 }
290316
291317 func (o *oracleRun) checkScreen() {
292318 s := o.screen
293- o.emit("screen %dx%d cursor=%d,%d vis=%t title=%q alt=%t", s.Columns(), s.Rows(), s.CursorRow(), s.CursorCol(), s.CursorVisible(), s.TerminalTitle(), s.AltScreenActive())
319+ o.emit("vt", "screen %dx%d cursor=%d,%d vis=%t title=%q alt=%t", s.Columns(), s.Rows(), s.CursorRow(), s.CursorCol(), s.CursorVisible(), s.TerminalTitle(), s.AltScreenActive())
294320 snap := s.Snapshot()
295- o.emit("modes %+v cursor %+v next=%d", snap.Modes(), snap.Cursor(), snap.NextRowID())
321+ o.emit("vt", "modes %+v cursor %+v next=%d", snap.Modes(), snap.Cursor(), snap.NextRowID())
296322 for y := range s.Rows() {
297- o.emit("row %d id=%d bound=%+v %s %q", y, s.RowID(y), snap.Bound(y), formatRow(s.RowCells(y)), rowText(s.RowCells(y)))
323+ o.emit("vt", "row %d id=%d bound=%+v %s %q", y, s.RowID(y), snap.Bound(y), formatRow(s.RowCells(y)), rowText(s.RowCells(y)))
298324 snapRow := snap.Row(y)
299325 if formatRow(snapRow) != formatRow(s.RowCells(y)) {
300326 o.t.Fatalf("seed %d: snapshot row %d differs from live row", o.sc.seed, y)
301327 }
302328 }
303- o.emit("bounds %+v", s.LineBounds())
329+ o.emit("vt", "bounds %+v", s.LineBounds())
304330 }
305331
306332 func (o *oracleRun) checkGraphics() {
307333 g := o.screen.GraphicsSnapshot()
308334 if g == nil {
309- o.emit("graphics nil")
335+ o.emit("graphics", "graphics nil")
310336 return
311337 }
312- o.emit("graphics gen=%d usage=%+v", g.Generation(), g.Usage())
338+ o.emit("graphics", "graphics gen=%d usage=%+v", g.Generation(), g.Usage())
313339 for _, a := range g.Assets() {
314340 blob := a.Blob()
315341 sum := sha256.Sum256(blob.Encoded)
316- o.emit("asset fmt=%v %dx%d px=%d sha=%x", blob.Format, blob.Width, blob.Height, blob.DecodedPixels, sum[:8])
342+ o.emit("graphics", "asset fmt=%v %dx%d px=%d sha=%x", blob.Format, blob.Width, blob.Height, blob.DecodedPixels, sum[:8])
317343 }
318344 for _, p := range g.Placements() {
319- o.emit("placement %+v", p.Spec())
345+ o.emit("graphics", "placement %+v", p.Spec())
320346 }
321- o.emit("fragments %+v", g.VisibleCellFragments(graphics.CellRect{Width: int64(o.screen.Columns()), Height: int64(o.screen.Rows())}))
347+ o.emit("graphics", "fragments %+v", g.VisibleCellFragments(graphics.CellRect{Width: int64(o.screen.Columns()), Height: int64(o.screen.Rows())}))
322348 }
323349
324350 func (o *oracleRun) checkHistory(deep bool) {
@@ -326,7 +352,7 @@ func (o *oracleRun) checkHistory(deep bool) {
326352 if h == nil {
327353 return
328354 }
329- o.emit("history len=%d cells=%d bytes=%d next=%d stats=%+v", h.Len(), h.Cells(), h.LogicalBytes(), h.NextRowID(), h.CompressionStats())
355+ o.emit("history", "history len=%d cells=%d bytes=%d next=%d stats=%+v", h.Len(), h.Cells(), h.LogicalBytes(), h.NextRowID(), h.CompressionStats())
330356 if !deep {
331357 return
332358 }
@@ -336,7 +362,7 @@ func (o *oracleRun) checkHistory(deep bool) {
336362 o.t.Fatalf("seed %d: MarshalHistoryTail: %v", o.sc.seed, err)
337363 }
338364 sum := sha256.Sum256(tail)
339- o.emit("snapview len=%d chunks=%d tail=%x", snapView.Len(), snapView.ChunkCount(), sum)
365+ o.emit("history", "snapview len=%d chunks=%d tail=%x", snapView.Len(), snapView.ChunkCount(), sum)
340366 var sealed [][]byte
341367 for i := range snapView.ChunkCount() {
342368 blob, err := vt.MarshalHistoryChunk(snapView.Chunk(i))
@@ -344,7 +370,7 @@ func (o *oracleRun) checkHistory(deep bool) {
344370 o.t.Fatalf("seed %d: MarshalHistoryChunk: %v", o.sc.seed, err)
345371 }
346372 sum := sha256.Sum256(blob)
347- o.emit("chunk %d %x", i, sum)
373+ o.emit("history", "chunk %d %x", i, sum)
348374 sealed = append(sealed, blob)
349375 }
350376 view := h.View()
@@ -358,7 +384,7 @@ func (o *oracleRun) checkHistory(deep bool) {
358384 o.t.Fatalf("seed %d: history Range: %v", o.sc.seed, err)
359385 }
360386 for i, row := range rows {
361- o.emit("hrow %d id=%d bound=%+v %s %q", i, view.RowID(i), view.Bound(i), row, texts[i])
387+ o.emit("history", "hrow %d id=%d bound=%+v %s %q", i, view.RowID(i), view.Bound(i), row, texts[i])
362388 if got := formatRow(view.Row(i)); got != row {
363389 o.t.Fatalf("seed %d: history Row(%d) differs from Range", o.sc.seed, i)
364390 }
@@ -386,16 +412,16 @@ func (o *oracleRun) checkHistory(deep bool) {
386412 o.t.Fatalf("seed %d: recovery transcript: %v", o.sc.seed, err)
387413 }
388414 tsum := sha256.Sum256(transcript)
389- o.emit("transcript %x", tsum)
415+ o.emit("history", "transcript %x", tsum)
390416 recovered, err := vt.NewScreenWithRecoveryTranscript(o.screen.Columns(), o.screen.Rows(), h.Limits(), sealed, tail, transcript)
391417 if err != nil {
392418 o.t.Fatalf("seed %d: NewScreenWithRecoveryTranscript: %v", o.sc.seed, err)
393419 }
394420 rh := recovered.History()
395- o.emit("recovered len=%d next=%d", rh.Len(), rh.NextRowID())
421+ o.emit("history", "recovered len=%d next=%d", rh.Len(), rh.NextRowID())
396422 if rh.Len() > 0 {
397423 rv := rh.View()
398- o.emit("recovered last %s", formatRow(rv.Row(rv.Len()-1)))
424+ o.emit("history", "recovered last %s", formatRow(rv.Row(rv.Len()-1)))
399425 }
400426 }
401427
@@ -406,7 +432,7 @@ func (o *oracleRun) render(step int) {
406432 if len(capture.Damage) != len(damage) {
407433 o.t.Fatalf("seed %d: CaptureDamage length %d want %d", o.sc.seed, len(capture.Damage), len(damage))
408434 }
409- o.emit("damage %+v", damage)
435+ o.emit("vt", "damage %+v", damage)
410436
411437 if o.mirror.Width != s.Columns() || o.mirror.Height != s.Rows() {
412438 o.mirror = core.NewFrame(s.Columns(), s.Rows())
@@ -428,11 +454,11 @@ func (o *oracleRun) render(step int) {
428454 o.t.Fatalf("seed %d step %d: ansi Prepare: %v", o.sc.seed, step, err)
429455 }
430456 out := prepared.Bytes()
431- o.emit("ansi %q", out)
457+ o.emit("ansi", "ansi %q", out)
432458 if o.r.IntN(7) == 0 {
433459 // Discarded draw: renderer must keep its committed shadow and damage
434460 // must remain pending for the next draw.
435- o.emit("ansi discard")
461+ o.emit("ansi", "ansi discard")
436462 } else {
437463 prepared.Commit()
438464 o.replay = o.applyReplay(o.replay, out, step, true)
@@ -444,7 +470,7 @@ func (o *oracleRun) render(step int) {
444470 if err != nil {
445471 o.t.Fatalf("seed %d: ansi256 Draw: %v", o.sc.seed, err)
446472 }
447- o.emit("ansi256 %q", other)
473+ o.emit("ansi256", "ansi256 %q", other)
448474 o.replay256 = o.applyReplay(o.replay256, other, step, false)
449475
450476 snap := s.Snapshot()
@@ -455,15 +481,15 @@ func (o *oracleRun) render(step int) {
455481 }
456482 hp, err := o.htmlR.Prepare(htmlSource, damage, false, html.Cursor{Row: cur.Row, Column: cur.Col, Visible: cur.Visible, Style: html.CursorStyle(cur.Style), StyleSet: cur.StyleSet})
457483 if err != nil {
458- o.emit("html err %v", err)
484+ o.emit("html", "html err %v", err)
459485 return
460486 }
461- o.emit("html %s", hp.JSON())
487+ o.emit("html", "html %s", hp.JSON())
462488 if o.r.IntN(6) == 0 {
463489 if err := hp.Abort(); err != nil {
464490 o.t.Fatalf("seed %d: html abort: %v", o.sc.seed, err)
465491 }
466- o.emit("html abort")
492+ o.emit("html", "html abort")
467493 } else if err := hp.Commit(); err != nil {
468494 o.t.Fatalf("seed %d: html commit: %v", o.sc.seed, err)
469495 }
@@ -491,7 +517,10 @@ func (o *oracleRun) applyReplay(replay *vt.Screen, out []byte, step int, styles
491517
492518 func runOracleScenario(t *testing.T, idx int) string {
493519 sc := oracleScenarioFor(idx)
494- o := &oracleRun{t: t, sc: sc, r: rand.New(rand.NewPCG(sc.seed, 0xdecaf)), h: sha256.New()}
520+ o := &oracleRun{t: t, sc: sc, r: rand.New(rand.NewPCG(sc.seed, 0xdecaf)), hashes: map[string]hash.Hash{}}
521+ for _, concern := range oracleConcerns {
522+ o.hashes[concern] = sha256.New()
523+ }
495524 if *oracleDump != "" {
496525 if err := os.MkdirAll(*oracleDump, 0o755); err != nil {
497526 t.Fatal(err)
@@ -541,16 +570,16 @@ func runOracleScenario(t *testing.T, idx int) string {
541570 if sc.history != nil {
542571 historyConfig = *sc.history
543572 }
544- o.emit("scenario %d %dx%d history=%+v byteSplit=%t evictHook=%t", idx, sc.cols, sc.rows, historyConfig, sc.byteSplit, sc.evictHook)
573+ o.emit("input", "scenario %d %dx%d history=%+v byteSplit=%t evictHook=%t", idx, sc.cols, sc.rows, historyConfig, sc.byteSplit, sc.evictHook)
545574
546575 var digests []string
547576 for step := range oracleSteps {
548577 o.maybeResize(step)
549578 chunk := o.genChunk()
550- o.emit("step %d write %q", step, chunk)
579+ o.emit("input", "step %d write %q", step, chunk)
551580 o.write(chunk)
552581 for _, e := range o.events {
553- o.emit("%s", e)
582+ o.emit("input", "%s", e)
554583 }
555584 o.events = o.events[:0]
556585 o.render(step)
@@ -558,12 +587,20 @@ func runOracleScenario(t *testing.T, idx int) string {
558587 o.checkScreen()
559588 o.checkGraphics()
560589 o.checkHistory(step%(2*oracleCheckEvery) == 2*oracleCheckEvery-1)
561- digests = append(digests, fmt.Sprintf("%02d/%03d %s", idx, step, hex.EncodeToString(o.h.Sum(nil))[:24]))
590+ digests = append(digests, fmt.Sprintf("%02d/%03d %s", idx, step, o.digest()))
562591 }
563592 }
564593 return strings.Join(digests, "\n")
565594 }
566595
596+// TestDifferentialOracle compares every checkpoint against
597+// testdata/oracle/golden.txt. Each golden line holds one digest per concern
598+// (see oracleConcerns), so an intentional output change shows which layers
599+// moved. Regenerate with -oracle.update only for a deliberate behavior change,
600+// on a full run, and justify the changed columns; diagnose a divergence by
601+// running -oracle.dump=DIR on both trees and diffing the scenario transcript.
602+// Under -race only every sixth scenario runs: scenarios are single-goroutine,
603+// so the detector adds cost without coverage.
567604 func TestDifferentialOracle(t *testing.T) {
568605 if testing.Short() {
569606 t.Skip("differential oracle skipped in -short mode")
@@ -572,6 +609,9 @@ func TestDifferentialOracle(t *testing.T) {
572609 t.Run("scenarios", func(t *testing.T) {
573610 for i := range oracleScenarios {
574611 t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
612+ if raceEnabled && i%6 != 0 {
613+ t.Skip("reduced oracle under -race")
614+ }
575615 t.Parallel()
576616 got[i] = runOracleScenario(t, i)
577617 })
@@ -580,28 +620,56 @@ func TestDifferentialOracle(t *testing.T) {
580620 if t.Failed() {
581621 return
582622 }
583- text := strings.Join(got, "\n") + "\n"
623+ ran := 0
624+ for _, digests := range got {
625+ if digests != "" {
626+ ran++
627+ }
628+ }
584629 if *oracleUpdate {
630+ if ran != oracleScenarios {
631+ t.Fatalf("-oracle.update needs every scenario; only %d of %d ran (remove -run filters and -race)", ran, oracleScenarios)
632+ }
585633 if err := os.MkdirAll(filepath.Dir(oracleGolden), 0o755); err != nil {
586634 t.Fatal(err)
587635 }
588- if err := os.WriteFile(oracleGolden, []byte(text), 0o644); err != nil {
636+ if err := os.WriteFile(oracleGolden, []byte(strings.Join(got, "\n")+"\n"), 0o644); err != nil {
589637 t.Fatal(err)
590638 }
591639 return
592640 }
593- want, err := os.ReadFile(oracleGolden)
641+ golden, err := os.ReadFile(oracleGolden)
594642 if err != nil {
595643 t.Fatalf("read golden (run with -oracle.update on a trusted baseline): %v", err)
596644 }
597- if string(want) == text {
598- return
645+ want := map[string][]string{}
646+ for _, line := range strings.Split(strings.TrimSpace(string(golden)), "\n") {
647+ want[line[:2]] = append(want[line[:2]], line)
648+ }
649+ for i, digests := range got {
650+ if digests == "" {
651+ continue
652+ }
653+ compareOracleScenario(t, fmt.Sprintf("%02d", i), strings.Split(digests, "\n"), want[fmt.Sprintf("%02d", i)])
599654 }
600- wantLines, gotLines := strings.Split(string(want), "\n"), strings.Split(text, "\n")
601- for i := range min(len(wantLines), len(gotLines)) {
602- if wantLines[i] != gotLines[i] {
603- t.Fatalf("oracle diverged at checkpoint %q (want %q); rerun with -oracle.dump=DIR on both trees and diff the scenario transcript", gotLines[i], wantLines[i])
655+}
656+
657+func compareOracleScenario(t *testing.T, id string, got, want []string) {
658+ t.Helper()
659+ for i := range min(len(got), len(want)) {
660+ if got[i] == want[i] {
661+ continue
604662 }
663+ gotFields, wantFields := strings.Fields(got[i]), strings.Fields(want[i])
664+ var moved []string
665+ for j := 1; j < min(len(gotFields), len(wantFields)); j++ {
666+ if gotFields[j] != wantFields[j] {
667+ moved = append(moved, strings.SplitN(gotFields[j], "=", 2)[0])
668+ }
669+ }
670+ t.Fatalf("scenario %s diverged at checkpoint %s in %v\n got %s\n want %s\nrerun with -oracle.dump=DIR on both trees and diff the transcript", id, gotFields[0], moved, got[i], want[i])
671+ }
672+ if len(got) != len(want) {
673+ t.Fatalf("scenario %s checkpoint count differs: got %d want %d", id, len(got), len(want))
605674 }
606- t.Fatalf("oracle checkpoint count differs: got %d want %d", len(gotLines), len(wantLines))
607675 }
@@ -78,21 +78,47 @@ type oracleRun struct {
78 // mirror reproduces the vev daemon consumer: one core.Frame reused and78 // mirror reproduces the vev daemon consumer: one core.Frame reused and
79 // mutated in place between draws, so renderer shadows must not alias it.79 // mutated in place between draws, so renderer shadows must not alias it.
80 mirror core.Frame80 mirror core.Frame
81- h hash.Hash81+ // hashes holds one digest per observable concern, so an intentional
82+ // change to one layer (for example ANSI bytes) leaves the others'
83+ // golden columns untouched and auditable.
84+ hashes map[string]hash.Hash
82 dump *bufio.Writer85 dump *bufio.Writer
83 events []string86 events []string
84 }87 }
85 88
86-func (o *oracleRun) emit(format string, args ...any) {89+// oracleConcerns are the golden columns, in output order. "input" covers the
90+// generated workload and VT callbacks; the others cover one layer each.
91+var oracleConcerns = []string{"input", "vt", "graphics", "history", "ansi", "ansi256", "html"}
92+
93+func (o *oracleRun) emit(concern, format string, args ...any) {
87 line := fmt.Sprintf(format, args...)94 line := fmt.Sprintf(format, args...)
88- o.h.Write([]byte(line))95+ h := o.hashes[concern]
89- o.h.Write([]byte{'\n'})96+ if h == nil {
97+ o.t.Fatalf("unknown oracle concern %q", concern)
98+ }
99+ h.Write([]byte(line))
100+ h.Write([]byte{'\n'})
90 if o.dump != nil {101 if o.dump != nil {
102+ o.dump.WriteString(concern)
103+ o.dump.WriteString(": ")
91 o.dump.WriteString(line)104 o.dump.WriteString(line)
92 o.dump.WriteByte('\n')105 o.dump.WriteByte('\n')
93 }106 }
94 }107 }
95 108
109+func (o *oracleRun) digest() string {
110+ var b strings.Builder
111+ for i, concern := range oracleConcerns {
112+ if i > 0 {
113+ b.WriteByte(' ')
114+ }
115+ b.WriteString(concern)
116+ b.WriteByte('=')
117+ b.WriteString(hex.EncodeToString(o.hashes[concern].Sum(nil))[:12])
118+ }
119+ return b.String()
120+}
121+
96 func formatCell(c core.Cell) string {122 func formatCell(c core.Cell) string {
97 return fmt.Sprintf("%q|%+v|%q|%q|%t", c.Rune, c.Style, c.Payload.Grapheme(), c.Payload.Hyperlink(), c.Continuation)123 return fmt.Sprintf("%q|%+v|%q|%q|%t", c.Rune, c.Style, c.Payload.Grapheme(), c.Payload.Hyperlink(), c.Continuation)
98 }124 }
@@ -284,41 +310,41 @@ func (o *oracleRun) maybeResize(step int) {
284 return310 return
285 }311 }
286 cols, rows := 8+o.r.IntN(110), 3+o.r.IntN(40)312 cols, rows := 8+o.r.IntN(110), 3+o.r.IntN(40)
287- o.emit("step %d resize %dx%d", step, cols, rows)313+ o.emit("input", "step %d resize %dx%d", step, cols, rows)
288 o.screen.Resize(cols, rows)314 o.screen.Resize(cols, rows)
289 }315 }
290 316
291 func (o *oracleRun) checkScreen() {317 func (o *oracleRun) checkScreen() {
292 s := o.screen318 s := o.screen
293- o.emit("screen %dx%d cursor=%d,%d vis=%t title=%q alt=%t", s.Columns(), s.Rows(), s.CursorRow(), s.CursorCol(), s.CursorVisible(), s.TerminalTitle(), s.AltScreenActive())319+ o.emit("vt", "screen %dx%d cursor=%d,%d vis=%t title=%q alt=%t", s.Columns(), s.Rows(), s.CursorRow(), s.CursorCol(), s.CursorVisible(), s.TerminalTitle(), s.AltScreenActive())
294 snap := s.Snapshot()320 snap := s.Snapshot()
295- o.emit("modes %+v cursor %+v next=%d", snap.Modes(), snap.Cursor(), snap.NextRowID())321+ o.emit("vt", "modes %+v cursor %+v next=%d", snap.Modes(), snap.Cursor(), snap.NextRowID())
296 for y := range s.Rows() {322 for y := range s.Rows() {
297- o.emit("row %d id=%d bound=%+v %s %q", y, s.RowID(y), snap.Bound(y), formatRow(s.RowCells(y)), rowText(s.RowCells(y)))323+ o.emit("vt", "row %d id=%d bound=%+v %s %q", y, s.RowID(y), snap.Bound(y), formatRow(s.RowCells(y)), rowText(s.RowCells(y)))
298 snapRow := snap.Row(y)324 snapRow := snap.Row(y)
299 if formatRow(snapRow) != formatRow(s.RowCells(y)) {325 if formatRow(snapRow) != formatRow(s.RowCells(y)) {
300 o.t.Fatalf("seed %d: snapshot row %d differs from live row", o.sc.seed, y)326 o.t.Fatalf("seed %d: snapshot row %d differs from live row", o.sc.seed, y)
301 }327 }
302 }328 }
303- o.emit("bounds %+v", s.LineBounds())329+ o.emit("vt", "bounds %+v", s.LineBounds())
304 }330 }
305 331
306 func (o *oracleRun) checkGraphics() {332 func (o *oracleRun) checkGraphics() {
307 g := o.screen.GraphicsSnapshot()333 g := o.screen.GraphicsSnapshot()
308 if g == nil {334 if g == nil {
309- o.emit("graphics nil")335+ o.emit("graphics", "graphics nil")
310 return336 return
311 }337 }
312- o.emit("graphics gen=%d usage=%+v", g.Generation(), g.Usage())338+ o.emit("graphics", "graphics gen=%d usage=%+v", g.Generation(), g.Usage())
313 for _, a := range g.Assets() {339 for _, a := range g.Assets() {
314 blob := a.Blob()340 blob := a.Blob()
315 sum := sha256.Sum256(blob.Encoded)341 sum := sha256.Sum256(blob.Encoded)
316- o.emit("asset fmt=%v %dx%d px=%d sha=%x", blob.Format, blob.Width, blob.Height, blob.DecodedPixels, sum[:8])342+ o.emit("graphics", "asset fmt=%v %dx%d px=%d sha=%x", blob.Format, blob.Width, blob.Height, blob.DecodedPixels, sum[:8])
317 }343 }
318 for _, p := range g.Placements() {344 for _, p := range g.Placements() {
319- o.emit("placement %+v", p.Spec())345+ o.emit("graphics", "placement %+v", p.Spec())
320 }346 }
321- o.emit("fragments %+v", g.VisibleCellFragments(graphics.CellRect{Width: int64(o.screen.Columns()), Height: int64(o.screen.Rows())}))347+ o.emit("graphics", "fragments %+v", g.VisibleCellFragments(graphics.CellRect{Width: int64(o.screen.Columns()), Height: int64(o.screen.Rows())}))
322 }348 }
323 349
324 func (o *oracleRun) checkHistory(deep bool) {350 func (o *oracleRun) checkHistory(deep bool) {
@@ -326,7 +352,7 @@ func (o *oracleRun) checkHistory(deep bool) {
326 if h == nil {352 if h == nil {
327 return353 return
328 }354 }
329- o.emit("history len=%d cells=%d bytes=%d next=%d stats=%+v", h.Len(), h.Cells(), h.LogicalBytes(), h.NextRowID(), h.CompressionStats())355+ o.emit("history", "history len=%d cells=%d bytes=%d next=%d stats=%+v", h.Len(), h.Cells(), h.LogicalBytes(), h.NextRowID(), h.CompressionStats())
330 if !deep {356 if !deep {
331 return357 return
332 }358 }
@@ -336,7 +362,7 @@ func (o *oracleRun) checkHistory(deep bool) {
336 o.t.Fatalf("seed %d: MarshalHistoryTail: %v", o.sc.seed, err)362 o.t.Fatalf("seed %d: MarshalHistoryTail: %v", o.sc.seed, err)
337 }363 }
338 sum := sha256.Sum256(tail)364 sum := sha256.Sum256(tail)
339- o.emit("snapview len=%d chunks=%d tail=%x", snapView.Len(), snapView.ChunkCount(), sum)365+ o.emit("history", "snapview len=%d chunks=%d tail=%x", snapView.Len(), snapView.ChunkCount(), sum)
340 var sealed [][]byte366 var sealed [][]byte
341 for i := range snapView.ChunkCount() {367 for i := range snapView.ChunkCount() {
342 blob, err := vt.MarshalHistoryChunk(snapView.Chunk(i))368 blob, err := vt.MarshalHistoryChunk(snapView.Chunk(i))
@@ -344,7 +370,7 @@ func (o *oracleRun) checkHistory(deep bool) {
344 o.t.Fatalf("seed %d: MarshalHistoryChunk: %v", o.sc.seed, err)370 o.t.Fatalf("seed %d: MarshalHistoryChunk: %v", o.sc.seed, err)
345 }371 }
346 sum := sha256.Sum256(blob)372 sum := sha256.Sum256(blob)
347- o.emit("chunk %d %x", i, sum)373+ o.emit("history", "chunk %d %x", i, sum)
348 sealed = append(sealed, blob)374 sealed = append(sealed, blob)
349 }375 }
350 view := h.View()376 view := h.View()
@@ -358,7 +384,7 @@ func (o *oracleRun) checkHistory(deep bool) {
358 o.t.Fatalf("seed %d: history Range: %v", o.sc.seed, err)384 o.t.Fatalf("seed %d: history Range: %v", o.sc.seed, err)
359 }385 }
360 for i, row := range rows {386 for i, row := range rows {
361- o.emit("hrow %d id=%d bound=%+v %s %q", i, view.RowID(i), view.Bound(i), row, texts[i])387+ o.emit("history", "hrow %d id=%d bound=%+v %s %q", i, view.RowID(i), view.Bound(i), row, texts[i])
362 if got := formatRow(view.Row(i)); got != row {388 if got := formatRow(view.Row(i)); got != row {
363 o.t.Fatalf("seed %d: history Row(%d) differs from Range", o.sc.seed, i)389 o.t.Fatalf("seed %d: history Row(%d) differs from Range", o.sc.seed, i)
364 }390 }
@@ -386,16 +412,16 @@ func (o *oracleRun) checkHistory(deep bool) {
386 o.t.Fatalf("seed %d: recovery transcript: %v", o.sc.seed, err)412 o.t.Fatalf("seed %d: recovery transcript: %v", o.sc.seed, err)
387 }413 }
388 tsum := sha256.Sum256(transcript)414 tsum := sha256.Sum256(transcript)
389- o.emit("transcript %x", tsum)415+ o.emit("history", "transcript %x", tsum)
390 recovered, err := vt.NewScreenWithRecoveryTranscript(o.screen.Columns(), o.screen.Rows(), h.Limits(), sealed, tail, transcript)416 recovered, err := vt.NewScreenWithRecoveryTranscript(o.screen.Columns(), o.screen.Rows(), h.Limits(), sealed, tail, transcript)
391 if err != nil {417 if err != nil {
392 o.t.Fatalf("seed %d: NewScreenWithRecoveryTranscript: %v", o.sc.seed, err)418 o.t.Fatalf("seed %d: NewScreenWithRecoveryTranscript: %v", o.sc.seed, err)
393 }419 }
394 rh := recovered.History()420 rh := recovered.History()
395- o.emit("recovered len=%d next=%d", rh.Len(), rh.NextRowID())421+ o.emit("history", "recovered len=%d next=%d", rh.Len(), rh.NextRowID())
396 if rh.Len() > 0 {422 if rh.Len() > 0 {
397 rv := rh.View()423 rv := rh.View()
398- o.emit("recovered last %s", formatRow(rv.Row(rv.Len()-1)))424+ o.emit("history", "recovered last %s", formatRow(rv.Row(rv.Len()-1)))
399 }425 }
400 }426 }
401 427
@@ -406,7 +432,7 @@ func (o *oracleRun) render(step int) {
406 if len(capture.Damage) != len(damage) {432 if len(capture.Damage) != len(damage) {
407 o.t.Fatalf("seed %d: CaptureDamage length %d want %d", o.sc.seed, len(capture.Damage), len(damage))433 o.t.Fatalf("seed %d: CaptureDamage length %d want %d", o.sc.seed, len(capture.Damage), len(damage))
408 }434 }
409- o.emit("damage %+v", damage)435+ o.emit("vt", "damage %+v", damage)
410 436
411 if o.mirror.Width != s.Columns() || o.mirror.Height != s.Rows() {437 if o.mirror.Width != s.Columns() || o.mirror.Height != s.Rows() {
412 o.mirror = core.NewFrame(s.Columns(), s.Rows())438 o.mirror = core.NewFrame(s.Columns(), s.Rows())
@@ -428,11 +454,11 @@ func (o *oracleRun) render(step int) {
428 o.t.Fatalf("seed %d step %d: ansi Prepare: %v", o.sc.seed, step, err)454 o.t.Fatalf("seed %d step %d: ansi Prepare: %v", o.sc.seed, step, err)
429 }455 }
430 out := prepared.Bytes()456 out := prepared.Bytes()
431- o.emit("ansi %q", out)457+ o.emit("ansi", "ansi %q", out)
432 if o.r.IntN(7) == 0 {458 if o.r.IntN(7) == 0 {
433 // Discarded draw: renderer must keep its committed shadow and damage459 // Discarded draw: renderer must keep its committed shadow and damage
434 // must remain pending for the next draw.460 // must remain pending for the next draw.
435- o.emit("ansi discard")461+ o.emit("ansi", "ansi discard")
436 } else {462 } else {
437 prepared.Commit()463 prepared.Commit()
438 o.replay = o.applyReplay(o.replay, out, step, true)464 o.replay = o.applyReplay(o.replay, out, step, true)
@@ -444,7 +470,7 @@ func (o *oracleRun) render(step int) {
444 if err != nil {470 if err != nil {
445 o.t.Fatalf("seed %d: ansi256 Draw: %v", o.sc.seed, err)471 o.t.Fatalf("seed %d: ansi256 Draw: %v", o.sc.seed, err)
446 }472 }
447- o.emit("ansi256 %q", other)473+ o.emit("ansi256", "ansi256 %q", other)
448 o.replay256 = o.applyReplay(o.replay256, other, step, false)474 o.replay256 = o.applyReplay(o.replay256, other, step, false)
449 475
450 snap := s.Snapshot()476 snap := s.Snapshot()
@@ -455,15 +481,15 @@ func (o *oracleRun) render(step int) {
455 }481 }
456 hp, err := o.htmlR.Prepare(htmlSource, damage, false, html.Cursor{Row: cur.Row, Column: cur.Col, Visible: cur.Visible, Style: html.CursorStyle(cur.Style), StyleSet: cur.StyleSet})482 hp, err := o.htmlR.Prepare(htmlSource, damage, false, html.Cursor{Row: cur.Row, Column: cur.Col, Visible: cur.Visible, Style: html.CursorStyle(cur.Style), StyleSet: cur.StyleSet})
457 if err != nil {483 if err != nil {
458- o.emit("html err %v", err)484+ o.emit("html", "html err %v", err)
459 return485 return
460 }486 }
461- o.emit("html %s", hp.JSON())487+ o.emit("html", "html %s", hp.JSON())
462 if o.r.IntN(6) == 0 {488 if o.r.IntN(6) == 0 {
463 if err := hp.Abort(); err != nil {489 if err := hp.Abort(); err != nil {
464 o.t.Fatalf("seed %d: html abort: %v", o.sc.seed, err)490 o.t.Fatalf("seed %d: html abort: %v", o.sc.seed, err)
465 }491 }
466- o.emit("html abort")492+ o.emit("html", "html abort")
467 } else if err := hp.Commit(); err != nil {493 } else if err := hp.Commit(); err != nil {
468 o.t.Fatalf("seed %d: html commit: %v", o.sc.seed, err)494 o.t.Fatalf("seed %d: html commit: %v", o.sc.seed, err)
469 }495 }
@@ -491,7 +517,10 @@ func (o *oracleRun) applyReplay(replay *vt.Screen, out []byte, step int, styles
491 517
492 func runOracleScenario(t *testing.T, idx int) string {518 func runOracleScenario(t *testing.T, idx int) string {
493 sc := oracleScenarioFor(idx)519 sc := oracleScenarioFor(idx)
494- o := &oracleRun{t: t, sc: sc, r: rand.New(rand.NewPCG(sc.seed, 0xdecaf)), h: sha256.New()}520+ o := &oracleRun{t: t, sc: sc, r: rand.New(rand.NewPCG(sc.seed, 0xdecaf)), hashes: map[string]hash.Hash{}}
521+ for _, concern := range oracleConcerns {
522+ o.hashes[concern] = sha256.New()
523+ }
495 if *oracleDump != "" {524 if *oracleDump != "" {
496 if err := os.MkdirAll(*oracleDump, 0o755); err != nil {525 if err := os.MkdirAll(*oracleDump, 0o755); err != nil {
497 t.Fatal(err)526 t.Fatal(err)
@@ -541,16 +570,16 @@ func runOracleScenario(t *testing.T, idx int) string {
541 if sc.history != nil {570 if sc.history != nil {
542 historyConfig = *sc.history571 historyConfig = *sc.history
543 }572 }
544- o.emit("scenario %d %dx%d history=%+v byteSplit=%t evictHook=%t", idx, sc.cols, sc.rows, historyConfig, sc.byteSplit, sc.evictHook)573+ o.emit("input", "scenario %d %dx%d history=%+v byteSplit=%t evictHook=%t", idx, sc.cols, sc.rows, historyConfig, sc.byteSplit, sc.evictHook)
545 574
546 var digests []string575 var digests []string
547 for step := range oracleSteps {576 for step := range oracleSteps {
548 o.maybeResize(step)577 o.maybeResize(step)
549 chunk := o.genChunk()578 chunk := o.genChunk()
550- o.emit("step %d write %q", step, chunk)579+ o.emit("input", "step %d write %q", step, chunk)
551 o.write(chunk)580 o.write(chunk)
552 for _, e := range o.events {581 for _, e := range o.events {
553- o.emit("%s", e)582+ o.emit("input", "%s", e)
554 }583 }
555 o.events = o.events[:0]584 o.events = o.events[:0]
556 o.render(step)585 o.render(step)
@@ -558,12 +587,20 @@ func runOracleScenario(t *testing.T, idx int) string {
558 o.checkScreen()587 o.checkScreen()
559 o.checkGraphics()588 o.checkGraphics()
560 o.checkHistory(step%(2*oracleCheckEvery) == 2*oracleCheckEvery-1)589 o.checkHistory(step%(2*oracleCheckEvery) == 2*oracleCheckEvery-1)
561- digests = append(digests, fmt.Sprintf("%02d/%03d %s", idx, step, hex.EncodeToString(o.h.Sum(nil))[:24]))590+ digests = append(digests, fmt.Sprintf("%02d/%03d %s", idx, step, o.digest()))
562 }591 }
563 }592 }
564 return strings.Join(digests, "\n")593 return strings.Join(digests, "\n")
565 }594 }
566 595
596+// TestDifferentialOracle compares every checkpoint against
597+// testdata/oracle/golden.txt. Each golden line holds one digest per concern
598+// (see oracleConcerns), so an intentional output change shows which layers
599+// moved. Regenerate with -oracle.update only for a deliberate behavior change,
600+// on a full run, and justify the changed columns; diagnose a divergence by
601+// running -oracle.dump=DIR on both trees and diffing the scenario transcript.
602+// Under -race only every sixth scenario runs: scenarios are single-goroutine,
603+// so the detector adds cost without coverage.
567 func TestDifferentialOracle(t *testing.T) {604 func TestDifferentialOracle(t *testing.T) {
568 if testing.Short() {605 if testing.Short() {
569 t.Skip("differential oracle skipped in -short mode")606 t.Skip("differential oracle skipped in -short mode")
@@ -572,6 +609,9 @@ func TestDifferentialOracle(t *testing.T) {
572 t.Run("scenarios", func(t *testing.T) {609 t.Run("scenarios", func(t *testing.T) {
573 for i := range oracleScenarios {610 for i := range oracleScenarios {
574 t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {611 t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
612+ if raceEnabled && i%6 != 0 {
613+ t.Skip("reduced oracle under -race")
614+ }
575 t.Parallel()615 t.Parallel()
576 got[i] = runOracleScenario(t, i)616 got[i] = runOracleScenario(t, i)
577 })617 })
@@ -580,28 +620,56 @@ func TestDifferentialOracle(t *testing.T) {
580 if t.Failed() {620 if t.Failed() {
581 return621 return
582 }622 }
583- text := strings.Join(got, "\n") + "\n"623+ ran := 0
624+ for _, digests := range got {
625+ if digests != "" {
626+ ran++
627+ }
628+ }
584 if *oracleUpdate {629 if *oracleUpdate {
630+ if ran != oracleScenarios {
631+ t.Fatalf("-oracle.update needs every scenario; only %d of %d ran (remove -run filters and -race)", ran, oracleScenarios)
632+ }
585 if err := os.MkdirAll(filepath.Dir(oracleGolden), 0o755); err != nil {633 if err := os.MkdirAll(filepath.Dir(oracleGolden), 0o755); err != nil {
586 t.Fatal(err)634 t.Fatal(err)
587 }635 }
588- if err := os.WriteFile(oracleGolden, []byte(text), 0o644); err != nil {636+ if err := os.WriteFile(oracleGolden, []byte(strings.Join(got, "\n")+"\n"), 0o644); err != nil {
589 t.Fatal(err)637 t.Fatal(err)
590 }638 }
591 return639 return
592 }640 }
593- want, err := os.ReadFile(oracleGolden)641+ golden, err := os.ReadFile(oracleGolden)
594 if err != nil {642 if err != nil {
595 t.Fatalf("read golden (run with -oracle.update on a trusted baseline): %v", err)643 t.Fatalf("read golden (run with -oracle.update on a trusted baseline): %v", err)
596 }644 }
597- if string(want) == text {645+ want := map[string][]string{}
598- return646+ for _, line := range strings.Split(strings.TrimSpace(string(golden)), "\n") {
647+ want[line[:2]] = append(want[line[:2]], line)
648+ }
649+ for i, digests := range got {
650+ if digests == "" {
651+ continue
652+ }
653+ compareOracleScenario(t, fmt.Sprintf("%02d", i), strings.Split(digests, "\n"), want[fmt.Sprintf("%02d", i)])
599 }654 }
600- wantLines, gotLines := strings.Split(string(want), "\n"), strings.Split(text, "\n")655+}
601- for i := range min(len(wantLines), len(gotLines)) {656+
602- if wantLines[i] != gotLines[i] {657+func compareOracleScenario(t *testing.T, id string, got, want []string) {
603- t.Fatalf("oracle diverged at checkpoint %q (want %q); rerun with -oracle.dump=DIR on both trees and diff the scenario transcript", gotLines[i], wantLines[i])658+ t.Helper()
659+ for i := range min(len(got), len(want)) {
660+ if got[i] == want[i] {
661+ continue
604 }662 }
663+ gotFields, wantFields := strings.Fields(got[i]), strings.Fields(want[i])
664+ var moved []string
665+ for j := 1; j < min(len(gotFields), len(wantFields)); j++ {
666+ if gotFields[j] != wantFields[j] {
667+ moved = append(moved, strings.SplitN(gotFields[j], "=", 2)[0])
668+ }
669+ }
670+ t.Fatalf("scenario %s diverged at checkpoint %s in %v\n got %s\n want %s\nrerun with -oracle.dump=DIR on both trees and diff the transcript", id, gotFields[0], moved, got[i], want[i])
671+ }
672+ if len(got) != len(want) {
673+ t.Fatalf("scenario %s checkpoint count differs: got %d want %d", id, len(got), len(want))
605 }674 }
606- t.Fatalf("oracle checkpoint count differs: got %d want %d", len(gotLines), len(wantLines))
607 }675 }
M screen_graphics_test.go +26 -0
@@ -3,6 +3,7 @@ package vt
33 import (
44 "encoding/base64"
55 "math"
6+ "runtime"
67 "strconv"
78 "strings"
89 "testing"
@@ -408,6 +409,31 @@ func TestScreenWriteReentrantFromCallbackKeepsOuterStreamIntact(t *testing.T) {
408409
409410 // The Screen borrows the caller's Write buffer while parsing; nothing it
410411 // retains may alias that buffer once Write returns.
412+// Base64 payloads padded with CR/LF decode into a buffer sized for the raw
413+// input. The scene must not retain that slack beyond its accounted bytes,
414+// otherwise untrusted output could hold memory past MaxEncodedBytes.
415+func TestScreenKittyNewlinePaddedPayloadRetainsOnlyAccountedBytes(t *testing.T) {
416+ const uploads, padding = 16, 1 << 20
417+ screen := NewScreen(16, 3)
418+ pad := strings.Repeat("\n", padding)
419+ var before, after runtime.MemStats
420+ runtime.GC()
421+ runtime.ReadMemStats(&before)
422+ for i := range uploads {
423+ screen.Write([]byte("\x1b_Ga=t,i=" + strconv.Itoa(i+1) + ",f=32,s=1,v=1;AQID" + pad + "BA==\x1b\\"))
424+ }
425+ runtime.GC()
426+ runtime.ReadMemStats(&after)
427+ require.Equal(t, uint64(4*uploads), screen.graphics.scene.Usage().EncodedBytes)
428+ for _, asset := range screenAssetBytes(t, screen) {
429+ require.Equal(t, []byte{1, 2, 3, 4}, asset)
430+ }
431+ // Untrimmed decode buffers would retain about 0.75 MiB per upload.
432+ growth := int64(after.HeapAlloc) - int64(before.HeapAlloc)
433+ require.Less(t, growth, int64(4<<20), "heap retained by %d padded uploads", uploads)
434+ runtime.KeepAlive(screen)
435+}
436+
411437 func TestScreenKittyGraphicsDoesNotAliasCallerWriteBuffer(t *testing.T) {
412438 scribble := func(b []byte) {
413439 for i := range b {
@@ -3,6 +3,7 @@ package vt
3 import (3 import (
4 "encoding/base64"4 "encoding/base64"
5 "math"5 "math"
6+ "runtime"
6 "strconv"7 "strconv"
7 "strings"8 "strings"
8 "testing"9 "testing"
@@ -408,6 +409,31 @@ func TestScreenWriteReentrantFromCallbackKeepsOuterStreamIntact(t *testing.T) {
408 409
409 // The Screen borrows the caller's Write buffer while parsing; nothing it410 // The Screen borrows the caller's Write buffer while parsing; nothing it
410 // retains may alias that buffer once Write returns.411 // retains may alias that buffer once Write returns.
412+// Base64 payloads padded with CR/LF decode into a buffer sized for the raw
413+// input. The scene must not retain that slack beyond its accounted bytes,
414+// otherwise untrusted output could hold memory past MaxEncodedBytes.
415+func TestScreenKittyNewlinePaddedPayloadRetainsOnlyAccountedBytes(t *testing.T) {
416+ const uploads, padding = 16, 1 << 20
417+ screen := NewScreen(16, 3)
418+ pad := strings.Repeat("\n", padding)
419+ var before, after runtime.MemStats
420+ runtime.GC()
421+ runtime.ReadMemStats(&before)
422+ for i := range uploads {
423+ screen.Write([]byte("\x1b_Ga=t,i=" + strconv.Itoa(i+1) + ",f=32,s=1,v=1;AQID" + pad + "BA==\x1b\\"))
424+ }
425+ runtime.GC()
426+ runtime.ReadMemStats(&after)
427+ require.Equal(t, uint64(4*uploads), screen.graphics.scene.Usage().EncodedBytes)
428+ for _, asset := range screenAssetBytes(t, screen) {
429+ require.Equal(t, []byte{1, 2, 3, 4}, asset)
430+ }
431+ // Untrimmed decode buffers would retain about 0.75 MiB per upload.
432+ growth := int64(after.HeapAlloc) - int64(before.HeapAlloc)
433+ require.Less(t, growth, int64(4<<20), "heap retained by %d padded uploads", uploads)
434+ runtime.KeepAlive(screen)
435+}
436+
411 func TestScreenKittyGraphicsDoesNotAliasCallerWriteBuffer(t *testing.T) {437 func TestScreenKittyGraphicsDoesNotAliasCallerWriteBuffer(t *testing.T) {
412 scribble := func(b []byte) {438 scribble := func(b []byte) {
413 for i := range b {439 for i := range b {
M screen_scroll.go +4 -0
@@ -108,6 +108,10 @@ func (s *Screen) emitLineEvicted(top, n int) {
108108 if s.history == nil && s.OnLineEvicted == nil {
109109 return
110110 }
111+ // Drop scratch sized for a much wider past geometry.
112+ if cap(s.evictScratch) > 2*s.frame.Width {
113+ s.evictScratch = nil
114+ }
111115 // Read boundaries and IDs before the caller rotates the frame: a soft link
112116 // belongs to the row it follows, and rotation reassigns row indices.
113117 for y := top; y < top+n; y++ {
@@ -108,6 +108,10 @@ func (s *Screen) emitLineEvicted(top, n int) {
108 if s.history == nil && s.OnLineEvicted == nil {108 if s.history == nil && s.OnLineEvicted == nil {
109 return109 return
110 }110 }
111+ // Drop scratch sized for a much wider past geometry.
112+ if cap(s.evictScratch) > 2*s.frame.Width {
113+ s.evictScratch = nil
114+ }
111 // Read boundaries and IDs before the caller rotates the frame: a soft link115 // Read boundaries and IDs before the caller rotates the frame: a soft link
112 // belongs to the row it follows, and rotation reassigns row indices.116 // belongs to the row it follows, and rotation reassigns row indices.
113 for y := top; y < top+n; y++ {117 for y := top; y < top+n; y++ {
M testdata/oracle/golden.txt +432 -432
@@ -1,432 +1,432 @@
1-00/019 55a72c4c8d1c1a0e00550a15
2-00/039 4beaddfc77e4110f80524b38
3-00/059 a5c2085be8baec4f551edd92
4-00/079 8bb94cfe1ed22a49a4a87e02
5-00/099 d575a05b8d36aabeed57f4bc
6-00/119 40726b31f079ddb1206aad61
7-00/139 22efecf809e0cb839cb073d5
8-00/159 543183f4a516938dc9348a4f
9-00/179 4e20ff78f152fcbe5137d54b
10-00/199 7037d94f724ee16e55d96bed
11-00/219 6fbae174dc09053ec6f6bd07
12-00/239 b9cc6a0d303e3b79c13f8d19
13-01/019 92d98f04143705d463e00d5a
14-01/039 0c887b0db21e564acbeb140b
15-01/059 4a1d21d32fb2e2dbb8a0a048
16-01/079 8c494398433b3f3292105b68
17-01/099 878ad5680b0b65efb2788c78
18-01/119 eba0201db6d4a0a544c7bc26
19-01/139 ce963cc5a23ffa5df867e30f
20-01/159 955c009f90fc40447bef222f
21-01/179 63624eaa51d667926773f7d6
22-01/199 742853e0e88b47c1d665f98b
23-01/219 c171d410ea73dbdc71607520
24-01/239 d009dd0730df60baf58c58a2
25-02/019 3e82372b6cb2ef730fbd402c
26-02/039 398deed5e521d0788101775d
27-02/059 21401dc4b8bee3c8c6dce2ff
28-02/079 22edd985876e2267fd4a6896
29-02/099 e6c6c10fcee0f3be94cdc63e
30-02/119 4cc31105a1fd3951dbc19e78
31-02/139 ff2da75e170b01030791f703
32-02/159 ee1b1a0baa2e690f004bac7c
33-02/179 70044ab48fec67d54592058a
34-02/199 73e6310d3e4c2a02a0aac70f
35-02/219 38ffab48e284151fed6243a1
36-02/239 dee6444cff6f5bdda9f190a1
37-03/019 23e37ad503fc5be744f00967
38-03/039 ec34adbb74097df59cc75e32
39-03/059 85c664d4a3ad1d484c5118b3
40-03/079 902369e3cf92b7cada2e9f20
41-03/099 008d777b9692c94433ca31e0
42-03/119 83d72044067f5276a4f75a4b
43-03/139 0cdea02f941f932699118d8e
44-03/159 dfd6d2abbad3a1be1e3d6ecc
45-03/179 99e59e60677d6d5ec88631a0
46-03/199 8fe8fc36ce8901c3bf214f23
47-03/219 a27e68abb075486983744a02
48-03/239 5eb1a5f31fda06ffcf7e74b8
49-04/019 4faa96c672855d38d5f009b9
50-04/039 45daf6da341e0be752176143
51-04/059 b210cfeb355ca92703eb5a7d
52-04/079 567e6224445b47f639d67406
53-04/099 36dfe5e3817a756a77610280
54-04/119 28f266be513510780e5298a0
55-04/139 77159aaa349724f6a3468083
56-04/159 454932ee14333813f68147b2
57-04/179 5dc2da5983a46d4d8c045463
58-04/199 33b567344c5ba4cbb11073b7
59-04/219 98d41d64e511dc4f992f9ddd
60-04/239 a873589f7cbf01ab97712424
61-05/019 68d508ff98ffe9c97d491512
62-05/039 22833aa6ac5590fd5c51a10c
63-05/059 f37316a5530d28ea4d386599
64-05/079 72697ed3d723a5e4e2bf127e
65-05/099 b8128a9baa2e24f9cc2b10d0
66-05/119 4f7d25dbe1b50ecf1ff67901
67-05/139 c269b4f1d67c5238d12fabc0
68-05/159 1ebdd92e38aeadf77e3d6c72
69-05/179 ffc342703ae6c3a8c4cd9f57
70-05/199 cb964d13d6ed459f435eca69
71-05/219 945a552afa3fc038c0d0d49d
72-05/239 bb39be7fce9c2c1f3a7dd6a3
73-06/019 9f70eb84e027a0da12cf789e
74-06/039 fd1b4d60360d797d01dcf980
75-06/059 e957cf36ed0da231cc781732
76-06/079 ef5a1e45228ec8d02b4339fb
77-06/099 8aee61a050bf383a74a62a8b
78-06/119 b63b5ac60fb59413621ca130
79-06/139 08d32c2a7d6a3d47faf8ad7e
80-06/159 ae180c731417adc39a3ac92e
81-06/179 50ecc3cc8de94af4fb6256e6
82-06/199 bcad1567aa6b13757337ca65
83-06/219 6d9e62599ea93901fbb98bda
84-06/239 12ad1caedd5346ab013bd936
85-07/019 771e7f8f79ce9d77f0bb56ff
86-07/039 031ed4ce8ac59a36ac7c1365
87-07/059 2516663f39582c63aa218218
88-07/079 3cd9f1f67cef906806422bdd
89-07/099 c3709b3f1a08717fc304d159
90-07/119 9ca36d78bfa961ac711edb07
91-07/139 fea50cc9d78951ce47ab7b5c
92-07/159 ac33e3c1365cc8c449a0d77b
93-07/179 92874af432d8106e7d39dd73
94-07/199 6a9cdfd7f92ce4e2fc62bc5d
95-07/219 40b3fb6542a9c48e6b1d5d03
96-07/239 10ecce8a3a41880bd86674e5
97-08/019 29e2816bc5d015ce2d23c05c
98-08/039 2a86fe7ff64d840cd8569737
99-08/059 51239ba60dc3b8f1b5078c45
100-08/079 abb48c671fe1388ddd3dbe91
101-08/099 bcfe3784a4f3cbe24d417126
102-08/119 039ca7a36109843550b4bbe2
103-08/139 0e6735e9400e34df32a24bc6
104-08/159 4cdce3dbee4325befd425faf
105-08/179 005758f8650f3cec82710cfe
106-08/199 52482d634ba2b06bf34693dd
107-08/219 1b3e53ed97faccd2061b9e26
108-08/239 c4ea1ea89908641b93e41266
109-09/019 4c119ea37ab5f5aaf7ab50f3
110-09/039 a1efea7a141d9b5481317d21
111-09/059 a0cce6141ccb877fe5e71f53
112-09/079 614e9de8720ed8292a34242d
113-09/099 fb69e78cf4ccaeba35c42a8a
114-09/119 52f16f33c2b608d3d6b59394
115-09/139 b9f02f6852f5de3b13640508
116-09/159 72b12cd005097c0ba898111c
117-09/179 06937b4778221356408d2ed2
118-09/199 369339d7370f38fcc22a12b9
119-09/219 b9eec1e382e0500d5f1edde7
120-09/239 c99a2183f2174d1e39502356
121-10/019 f1b345ef33635fe6028f81b4
122-10/039 bb0ee5ddb6ba0461e8747c48
123-10/059 7b0a1d3c4fcef2b20317695f
124-10/079 9d002061162fa4fab0050bcd
125-10/099 3878530870a8fb56b8328017
126-10/119 620d17d70aa0ae092bfe7fe0
127-10/139 5d8a36f80fa538d941383259
128-10/159 4f464ea644caecec04f35afc
129-10/179 c60434e2aa9d7a64724ca147
130-10/199 b9f0bdae9c7a31f6ca8bcbe6
131-10/219 14e56199cd1442fc6793d65b
132-10/239 8c43ab2d5bde3b2fda977ddd
133-11/019 c93975e62fac424f33e30dbd
134-11/039 d346876e1b164d0cd0627c43
135-11/059 01e960a0c2e2ff6e67700683
136-11/079 1dc0f11f0abb3b5fc9f24e7c
137-11/099 08d0c2c91fc7f7b8bc077073
138-11/119 c25c0212819cece6d0639b16
139-11/139 05f7ae1225aab0d0cf837327
140-11/159 0b421f3d3607eed3fdd06a22
141-11/179 dd0db71df59ff3782d710188
142-11/199 8f76f1ddbcb47375a2539363
143-11/219 82ad6598f848e6ed7ab84f16
144-11/239 581acb7b5585a2cb9127aabe
145-12/019 4fade3921f5735064355eec1
146-12/039 4752e78884537c49b3a981a6
147-12/059 8d24a113e07ffe7f2ee85d92
148-12/079 b664d979cc6ff5402f46feb5
149-12/099 71a4e7544cc95fed335b866a
150-12/119 f3e962c48f6477dc9e36cba6
151-12/139 88ad314b543b01991001d0ff
152-12/159 c496c6f531b311b533c5d8dc
153-12/179 902d77ceb40bc233976eab25
154-12/199 ae45efdbdedea0732816ddd9
155-12/219 a9b16863b78bef550c8f3a45
156-12/239 42f9034b8b4fd71772b18bb3
157-13/019 ef8a3432b61607340356a764
158-13/039 4e823b712c6aab07bcd5764e
159-13/059 90b7e616d2c528faeee0f72b
160-13/079 b1330a7079b795346ee9e317
161-13/099 9f0d10089131edf34cceb0a1
162-13/119 069d5dc52bcfba2eaa2211bd
163-13/139 08b97ef26faddb637a424bef
164-13/159 c29b028480ce1c097e8c3066
165-13/179 85d6cc0d0267ce57c4f438d7
166-13/199 84a14ed35e312f14e0c4d220
167-13/219 8382c4d6025f22cddd967535
168-13/239 4e3ac44cff6dfa7d7a843378
169-14/019 747d54cdf75a492242809318
170-14/039 e6530a9282bd6095e15a9677
171-14/059 715de56023e1afc30c1feea1
172-14/079 f5c6253e95d471ccf7892526
173-14/099 09063bb10e3e19d067c9c85c
174-14/119 f8753c5d5010cd747e5dcc31
175-14/139 8a726baa028acc349f76fcb5
176-14/159 6707de5fd29ec469ba8913b9
177-14/179 3914c9045ccb2d16f6dfb386
178-14/199 f5992df3d18c885bcaab4496
179-14/219 38e1a9fe90723b701c438464
180-14/239 c90fb86719f7e4613e3720c2
181-15/019 95e07748c709fa34a80ceff7
182-15/039 17f763741791d1ce05af5d23
183-15/059 91afaa9890df8d7e1704a824
184-15/079 f7b444177e7de8fbd6ffb68c
185-15/099 c1a6b419a58119e00553b73b
186-15/119 e087eec2596edb2fbb67b309
187-15/139 2f6949b8d82d85d0ed0e1945
188-15/159 d870e1d84bf822c53958e42e
189-15/179 e61ad13af00d508f72ca02e9
190-15/199 c2e3de3f26a36097e8df792e
191-15/219 6d50c5b64eca9d2ece1e3556
192-15/239 6c7b58a0ed8591a241ab438d
193-16/019 4314babccb7675abd6328c32
194-16/039 3e6ee1b339dab4ff5e0c8b34
195-16/059 1afd8504d6a0be4d6cc9c3c3
196-16/079 50f71b7a9d7c444810cf1ba6
197-16/099 65a1c2e6e41adcddbc510efc
198-16/119 3f7c33fe85ccde2210b37f8f
199-16/139 1b47397842763e30313e66de
200-16/159 3d9b4904b96244df64051cc7
201-16/179 60ae20b4cabf7c1a02192010
202-16/199 210f0c4ad73131d2b465b362
203-16/219 4b62676c69410e9b6f9d8f26
204-16/239 72f70f009e426f88b33ebdae
205-17/019 1a06602479d8e795ee95c965
206-17/039 c7e7eb54ee63d9e7e23ceaca
207-17/059 51c34ba1a80d55b1f9ae42fa
208-17/079 d5f10d70e10e0e87e54ac6f3
209-17/099 0a3784787eb2a97cce6c8309
210-17/119 7ccd8bedfbf26111e264baa5
211-17/139 f028c427efd1ce9c0b9828d1
212-17/159 fb8b3eb57ac4186345d52918
213-17/179 1c7da7757137c15d7a05d3d4
214-17/199 55b35801df62b3250963613d
215-17/219 1cb11bbb2c5dd8995094be53
216-17/239 6a146a19d7c534c4766e98f8
217-18/019 a1d2576637f54892892ea0b4
218-18/039 4415a2923a28b75a5aa0dbfb
219-18/059 2bac49c23f1c09f170c68dc2
220-18/079 eeebf8f57f35ee0b110fc200
221-18/099 e3673a14664b853fa9613c64
222-18/119 57aa1250c9bb46869c8fc1a7
223-18/139 abaca7067643db7db4dfe105
224-18/159 6e878b08b5635eac7ab9816c
225-18/179 031a000b34a4ba3bc6cedc53
226-18/199 c523b55eb720c065fc6134ac
227-18/219 0f367277325b630ce5bc634f
228-18/239 e04b873c6820a46bfd2f4873
229-19/019 2db955914f2e068e72cf8dfa
230-19/039 ec344560f2bb7de5f25fdb78
231-19/059 d1a41ae321f1449d256cf19d
232-19/079 8faf99af914b67a155d5ec77
233-19/099 4e1d07972fad7ea30ae47405
234-19/119 25c71afea29fbd715e2a4475
235-19/139 c6aa86c0ecbc79508ca55d21
236-19/159 f4f99d1ac2eb88ec22a12895
237-19/179 48e52a38bcee4b40556c3ad5
238-19/199 0000d0003982f1b02a05c031
239-19/219 8a3fe5821bfca2452396d384
240-19/239 f80259caca42e4bec5999fbd
241-20/019 3c776bd6d460be5f6bcd060e
242-20/039 ef65b757bd137499a352d5ae
243-20/059 1cfcab4ffbc08c619e97bcd5
244-20/079 8879e2856d1a555f07aa60d7
245-20/099 e16919d7e8c9f20f7dfa5956
246-20/119 cb7f9cf61ef176f01706ac77
247-20/139 f9edefe5603a815455b563ff
248-20/159 cf8862d058a774e0fdb18628
249-20/179 abfad109898597588888b96d
250-20/199 a619ae4048d75c8eb123bc03
251-20/219 e97c8dda4681c61c2597a6b6
252-20/239 d3c1276233a20ff99b540e84
253-21/019 357ece3eab75324d3823a6a4
254-21/039 fe4501bedc7017bc40ff0509
255-21/059 c97dc13dbcd996b58361777e
256-21/079 478d3efcfcca35aac31016e5
257-21/099 3311dde300dcf85626edb8b7
258-21/119 67ff6fbebbb9976f9f5191d8
259-21/139 034216a3e7d38b221d5a8811
260-21/159 adc62b539970ad3123cb4175
261-21/179 0323505afc602891ba38d7ac
262-21/199 2c8eb6ab3e644c91102d47c5
263-21/219 c88b6d036e56dd9bf2772e84
264-21/239 1541f980765b4f40cd846615
265-22/019 6fc626ac7796049f3457a9a7
266-22/039 e9214d74742e6ab1a1c8baf0
267-22/059 72e63b2a0100e4153851a23d
268-22/079 9b1a8ebe1c432db2fedb68e3
269-22/099 924e3f255fb856ff7b7dc8ed
270-22/119 53fcd1df652d602fe412c5a0
271-22/139 7414a5f8fdbd506ab15f698d
272-22/159 bc2dd2281c12435224135073
273-22/179 dfeef83df0e865e875132be1
274-22/199 9fe1387f10258c696fd9e783
275-22/219 3009560abe632e04450f7f41
276-22/239 fe8d129db62a73ae9b9650bf
277-23/019 20cb94d03695ad09763e03d2
278-23/039 6c18ee020345a7699fd75494
279-23/059 f85c5ecebab82f1126f3c964
280-23/079 2fbeda367e9d56072d5b0edc
281-23/099 307896059fd55149f9d7c7e3
282-23/119 73bafc1697a5e247b2d3c75f
283-23/139 214cbbca9ce4b1d0c98ea569
284-23/159 82259d749685c0f294be858f
285-23/179 8d7b14f89c5f5d3113fbb3d2
286-23/199 ddee2d89e0897e90f9a6df78
287-23/219 65e4440830b9f98e48fe3a11
288-23/239 e8ca9cf0699b2c6333e0cb3e
289-24/019 b7fdbacf57cb0af4d47225ba
290-24/039 a6c7f740d5d06f67495f9e33
291-24/059 43a01382b5ac0c1ae9bed9cc
292-24/079 b1920c5092ae3660a5d16b80
293-24/099 6c5e0cce477b33f47b106ea3
294-24/119 6d6f085ab19ecfad1a4a2120
295-24/139 9547bae694f87fb2c2b3d311
296-24/159 4acc87c8a3480147416549a0
297-24/179 e0f7f82de3ea5bbb6bc4c259
298-24/199 accc2199dff19d266f855064
299-24/219 a763e81bff4e145b46922cf3
300-24/239 5299c46a14f4fa125c9b8611
301-25/019 eb73f8f3bb46422a6a12fc8f
302-25/039 823c96945f71196e67f10f65
303-25/059 c04f006b9f600ecd075cec6a
304-25/079 a21fe1e939c9fa2ddbc2d385
305-25/099 c20fca1d42014ae0701d6d0b
306-25/119 3b6b3af160572b8ebc24277f
307-25/139 e6151bf8cfffc442059ea129
308-25/159 5209600fc448f453bd687cb2
309-25/179 043175bc5eea52c09fb8f884
310-25/199 4b7c1cd9781ec41bf596b764
311-25/219 ad62688c776574ab5c442de7
312-25/239 22e025d483651540c55002c6
313-26/019 122c0cce3cc0ece13ce6f89a
314-26/039 0999ef9b5da72bc75cef9d49
315-26/059 2efdbf6da4b726f10f2878d1
316-26/079 f899906f635ddb86d5c73984
317-26/099 46367bf24897cad56dd5235c
318-26/119 a97b04bc18332773595951da
319-26/139 c5ae15a2b57146ef155e27b9
320-26/159 51ab1eaae8be298680367404
321-26/179 e35bdd23c19b6295280181ed
322-26/199 5f21c27026ba98b0a9d5d51c
323-26/219 2fcb984adf0b347e0da88d33
324-26/239 200f40ed44f86ce04857c1ef
325-27/019 ee2c010c41b9f0e5f70ce2b3
326-27/039 91ab08fb270466abbfb06c54
327-27/059 2e73fe488420a5de3866e7e3
328-27/079 a72a80db0e8ee9bffb891b38
329-27/099 917cde1321cfce583a63d9f2
330-27/119 b8056ec6e08df1e2f7033b6a
331-27/139 22214c1a34de027d97f18ad9
332-27/159 18debaf4cd5dfd2bb665bf34
333-27/179 b8c41633f2ea27468edc411a
334-27/199 85bc90436e42fca40bd64d3c
335-27/219 f0dbe3da68c8dd144c3dd9b7
336-27/239 214002b3d936e2fe396aae01
337-28/019 3ee1c2f031af3ad67ae50ebc
338-28/039 07508b3af21ec20fadeefe55
339-28/059 dfa63544d3d6a817a9212067
340-28/079 237f6a260f672d353323e622
341-28/099 3fa387d797ef0467f5e6e7e3
342-28/119 e25b9e12f6c5b3b03510cc14
343-28/139 1740ba1423fde72696b1cb5f
344-28/159 087e829214051615d334f3ef
345-28/179 86a425ae6b5b0e26b2d91ade
346-28/199 38502b27dac76ac25e7d8b3b
347-28/219 407ae66e6aa5fd9602e5e5ce
348-28/239 b2630d52745798f40a5a034d
349-29/019 72e981fc506bfdd3bbf15c37
350-29/039 8c46bcf213fe0e9cf159a7d2
351-29/059 213c8dd3d5bcda3abb11ab05
352-29/079 5c42ca0bf2bdde3f4e8beb0e
353-29/099 9da53eccca7406686de96ec0
354-29/119 c91f989577473d295e74d700
355-29/139 6d5ff6bc1b1b73cae023806b
356-29/159 a1e1bfef4df06dc65e727a5e
357-29/179 afb819e69c5c53d51d49d446
358-29/199 78df663b24d8507a469a7959
359-29/219 e40592fde61b5e14bf73242a
360-29/239 b6629ebed5f6c79374cf4cb8
361-30/019 ea74787caee42ed3665575ed
362-30/039 91b5e5afa5d3bb06b087f6ad
363-30/059 ab536abe78f0cf27cdf94a75
364-30/079 cb0e90a99459de9ed8493a87
365-30/099 24cda2b6890297d9254603d1
366-30/119 dc93cdf4c2014d22ac4d1ef2
367-30/139 66e5417af5336b68e70cfa14
368-30/159 c10f3ab9c58aa3f43caa4f94
369-30/179 a7d6695e7add8ed6e7912161
370-30/199 f1fe2d3081c9ccfc7413e3a9
371-30/219 5c1dad4fffc15226a5eebe51
372-30/239 966ff4c469452f7951326c5e
373-31/019 869af9273a068555a7c65e06
374-31/039 af9002bdf228a2e1f034df74
375-31/059 375fd592eea7fdb3ce4a7563
376-31/079 8d6f8e9a242c0da7a8707d06
377-31/099 f4e05fd0482cb95b1141b933
378-31/119 0499dd21ead9843ec3668589
379-31/139 8fab9f1300b2d8c6757a9587
380-31/159 e5ea9bef6d0ff097b0b0f00f
381-31/179 2d21760a2b468c1f8e101b86
382-31/199 1c76b93d064c496485782148
383-31/219 8a23244f3e0b25b774aaabbb
384-31/239 6b47e6b3998cf340d47f2dc9
385-32/019 ed11b0c6e02dfce865d49934
386-32/039 bd3bbe698e10adf1f5fbc490
387-32/059 fb530e83cb69ec498ccd32a7
388-32/079 f54210cbb277563ac36c611d
389-32/099 9f2557fef0b33c2da3b1e22b
390-32/119 4b02e8f56434d83e8f5234f6
391-32/139 39feab897a9120d585c20a8e
392-32/159 d0953ad716ea690de47dfc3d
393-32/179 f6a7b77c5991d37449e779b1
394-32/199 2c188342e677e30c8ffe7f9e
395-32/219 7fc717e4fbfd57748ab342e3
396-32/239 506a3d22b3e2ff760873e0fb
397-33/019 75e34d5589c8f836a06d090e
398-33/039 372c230667e378656b2af4ff
399-33/059 938b86084dbb06afa4454b27
400-33/079 7fa7265281d43e73b797d780
401-33/099 ac83290b711b8dec3003df47
402-33/119 021ac2bab909abdd6e5c77b5
403-33/139 ed69b8d8881a85100d32c4cd
404-33/159 c1566ad91ec422c65923fe34
405-33/179 9275113b9df0b001112ad573
406-33/199 a269fac1fd59ac746cdcc3ed
407-33/219 8efc32f7b432b011f6862afb
408-33/239 360719a27cebdd0863b2e775
409-34/019 93dcae1fc2bfd6779aff1aff
410-34/039 e4c849c2eb75db26ab3e4a69
411-34/059 f44f95efd2e73205143c656c
412-34/079 500ac8d59cbff22ad8cedf95
413-34/099 8cde09d8fb843f0771e27c68
414-34/119 8888149eafa436929ba9002f
415-34/139 9c9180251a5d41fb6bb84e0e
416-34/159 a8c9c943771f1bac64729951
417-34/179 147dc1d5ce1aa53965747a76
418-34/199 d60cdab9e926b1a975ab7c68
419-34/219 70311db1c213b30d8622a677
420-34/239 16c8a61f803eef432762550b
421-35/019 6ce6075f205b75f864a11ca6
422-35/039 8375248e74a353fc4ec62d73
423-35/059 794e546c0d3346dc3965043f
424-35/079 f4a4a12dd0c59cfa3a7036b4
425-35/099 a424a229392a35da8d937062
426-35/119 5e71329265c6c2ddfdebda4d
427-35/139 6aa980472b2f18fe51c96a53
428-35/159 c677d854790176770b89c39b
429-35/179 aa982fd9d111a2bfe2cd0342
430-35/199 ce9d070f4fa6d77de1426eca
431-35/219 a867713adf7f878aaac51716
432-35/239 336185b759391ae1b9650572
1+00/019 input=34fc58104b22 vt=bb9b826cf048 graphics=c1313fa59940 history=e3b0c44298fc ansi=558b1d465cb9 ansi256=7c62df9f88a6 html=57085dbc6bc7
2+00/039 input=957f13b6dc6d vt=d580503f0b0c graphics=d9a508723211 history=e3b0c44298fc ansi=d8801a468cd2 ansi256=4e4fbb5a75ae html=6f9f51bb389f
3+00/059 input=02ca4e7f645d vt=8f0ec905b4dd graphics=ca7e3df19c59 history=e3b0c44298fc ansi=22e9db71432b ansi256=c94537d35e21 html=77e2381b2833
4+00/079 input=e7459a0424b7 vt=658a98490259 graphics=2294ead167f8 history=e3b0c44298fc ansi=a769731d8a6b ansi256=dfaab9ed690b html=9331f082e0c7
5+00/099 input=65861d80c11d vt=3dff2abbe571 graphics=49a531a5cac2 history=e3b0c44298fc ansi=b9610fa412a9 ansi256=d9a001c8d0d3 html=bdcab0b42f1b
6+00/119 input=b7bbd6cab918 vt=802dc307f264 graphics=4dca1d671bb5 history=e3b0c44298fc ansi=94ed76fcf0d5 ansi256=cdeba8de8f99 html=b646697de0df
7+00/139 input=e1957aa581c4 vt=e59eed292827 graphics=c7edbf6bb08c history=e3b0c44298fc ansi=bf1cd5adba0c ansi256=4b00e8ef793c html=73f7506b9438
8+00/159 input=72d2e266bbee vt=ce72286ff858 graphics=9d08071cbfe7 history=e3b0c44298fc ansi=3473f0b036d2 ansi256=7caddc9fa2d8 html=6a98d3bd5931
9+00/179 input=5f03942bb446 vt=909794a3080a graphics=c4be9e09c930 history=e3b0c44298fc ansi=43919248cf80 ansi256=15e239bd6430 html=23461097c399
10+00/199 input=537e6ea131ba vt=ed5b1e654b14 graphics=be52bd862e04 history=e3b0c44298fc ansi=77868d0f1ea5 ansi256=91351ed686ae html=4e7ba65fd552
11+00/219 input=0d15f7a3b67c vt=4fa431325c0d graphics=79964969d8b4 history=e3b0c44298fc ansi=1dfbb31f7937 ansi256=0929b8057746 html=582bc75c8e8d
12+00/239 input=7c8d6d2373ed vt=bb9c175f8153 graphics=9e5082990084 history=e3b0c44298fc ansi=2ccb101439ce ansi256=7d50c7faac48 html=a98bb992d270
13+01/019 input=cbc8877bed63 vt=22ab1acff1bf graphics=c5b8fe57cfa6 history=fa5d8f18f68d ansi=afdab3ddfac9 ansi256=48c65d2c43e6 html=02caebc851dd
14+01/039 input=d0cb0bd869c9 vt=f58c883883ec graphics=22628079d8b2 history=386f8088a60f ansi=d592741d1509 ansi256=fac3d9aee1ab html=bde87d40c7e5
15+01/059 input=e25ff0ff1a54 vt=f329087d99d8 graphics=033cd4eb10d0 history=241434fd3fed ansi=d6547cc1881f ansi256=6e78b18137e7 html=578f8efbaa40
16+01/079 input=4de36294e2e7 vt=0b491efe74c5 graphics=e3e861b21b99 history=3e3751cacfa6 ansi=36b333e14ee3 ansi256=f581315254ff html=7a358839f40a
17+01/099 input=2b7fa8b73e54 vt=cdcf0feb0ab2 graphics=7b1785222ace history=6de5f14c9b3b ansi=318c8c763741 ansi256=edeaafe2bf97 html=a6cc5cc4dc10
18+01/119 input=ed4026577ede vt=47cfe6da14c5 graphics=1f4e90d00dbe history=9fc31e684946 ansi=511a067be740 ansi256=075aaf679ea9 html=5ba0d816280d
19+01/139 input=16d884839d5e vt=b47acf684680 graphics=aba320d6ac2d history=c694cebc9c6d ansi=a21c3e6b2c56 ansi256=d66750dd1f13 html=7bfd11f66888
20+01/159 input=ae726a283ab9 vt=124d96154247 graphics=7c92abaf9499 history=1b394f493a6e ansi=e9bb095ab5e8 ansi256=c6e07402bca0 html=60840af2b8ab
21+01/179 input=4002bcdef56c vt=ae28edda6428 graphics=874c3d3632c4 history=f97e91c814bf ansi=1476dc66f1dc ansi256=e3d9c1c5f152 html=377eadb17b87
22+01/199 input=bcdb0bb395af vt=6c6a86726ea6 graphics=408aa5c32aed history=cc247d46dc5d ansi=3900e39db02f ansi256=a1003c8fd5ad html=0ec54e438114
23+01/219 input=b57a1b43c9ed vt=33212d08cac6 graphics=915c35a9e421 history=55df44fba064 ansi=a697afce6763 ansi256=4afd404912f3 html=6f57720f0bcc
24+01/239 input=5a6d7e54e43f vt=064445a04eb4 graphics=08fa69ab8d7e history=ae06c8614ee7 ansi=ec529ccb7d82 ansi256=da4537b03b71 html=e176c4d39894
25+02/019 input=e128155ff5ee vt=6165a679180d graphics=9258c91bf1d0 history=417faca887a1 ansi=c76da783dd51 ansi256=ade5d4699a5a html=5c12498e7f09
26+02/039 input=f55b6f5f0ae5 vt=6c13343e5e72 graphics=ec94ae6cc7b9 history=a98f1d645add ansi=9d23bdd6b42f ansi256=34b777e364eb html=7421f1e2339e
27+02/059 input=efecbfa91a37 vt=f15094e108a2 graphics=2cc2c4f89334 history=c354c025cf5c ansi=31a27bd463dc ansi256=f7cb938291b9 html=d1172b288064
28+02/079 input=5569bc9cc096 vt=d49d527484f7 graphics=20fb47c1a763 history=5ee55bc12a28 ansi=2dc804e97027 ansi256=6f3132f4c824 html=cf0a7fd2cd04
29+02/099 input=818abcb54d25 vt=79b2c236e761 graphics=2988687caeb9 history=772aefdee759 ansi=eaa23edb44d4 ansi256=f0c638352747 html=e975b06011c0
30+02/119 input=0953c14a91ab vt=3255a5b7edd4 graphics=66394393cb3e history=40e37b86d83b ansi=ac12ac48a6d9 ansi256=786be89622e7 html=c2a8cbe382cd
31+02/139 input=097eb426b6af vt=cd9241f4e821 graphics=985e13b357ae history=d0c1aa3cc624 ansi=81d1a99de839 ansi256=465cdb5a2331 html=a4153acb0e41
32+02/159 input=38bd63bbb187 vt=c6a6eaea70b2 graphics=aa9d4f7d2ef7 history=0de5f5ec693d ansi=6ac3fb8d4c15 ansi256=6d6993b9a7fc html=e2cbed3a72e5
33+02/179 input=8ae111814233 vt=8fbc292c149b graphics=411e2f4f1d49 history=fdf4efdc191b ansi=abf0b4964a01 ansi256=2a7e59c820a8 html=5369dcb88366
34+02/199 input=4213f245636c vt=c1d2f7fb395a graphics=5bfa4713d56a history=f5e53a839d08 ansi=7e4c5ba3abb2 ansi256=d2aa15e8b380 html=48adffbac091
35+02/219 input=931fd5b7147d vt=c659827ccda1 graphics=1651f31f454f history=98009e23090b ansi=fe65923b0e7d ansi256=c7537bce4e9d html=f7dd3b851411
36+02/239 input=8176a5e301c3 vt=c9d8342717ba graphics=fa8374156c82 history=09807ad0d1da ansi=8f8756e5bd05 ansi256=b6612363d590 html=98d729501758
37+03/019 input=77c9efeb3d0d vt=9dd67d6ea65f graphics=32c8e22c58c9 history=9b00e5d5c883 ansi=bd1117ecc4ef ansi256=215c0a0c57b1 html=c8d2199048c7
38+03/039 input=935cc14c51ee vt=b936be15b17e graphics=fa83d34babef history=53a5b6b99603 ansi=4dbccd5407c6 ansi256=1a21508da4df html=743c05c22684
39+03/059 input=ecb91d159cb1 vt=e4fceadf53cc graphics=6ee88ceadd09 history=6f799dd4518c ansi=c7f5ad8c750c ansi256=ba17a1f0e9e4 html=390e3c978264
40+03/079 input=cc2cd5bf9438 vt=5dd5e31dc91c graphics=a6faff22c0fb history=4c160d4c8f45 ansi=6eb8fa2cbfe8 ansi256=f575b7123b3e html=19a9a215197c
41+03/099 input=34c42410c4ec vt=89b335bd0924 graphics=ca98374af1a4 history=a1f40bab9f65 ansi=9286621ea5a3 ansi256=13c85dde6f2b html=2f2809220157
42+03/119 input=699e8fffe957 vt=dcffdbdd8be9 graphics=cb0060e5f99a history=9abbb7c01a69 ansi=ee808efefd2c ansi256=9817a2a6e477 html=7f2515b0d4c5
43+03/139 input=54491f16453e vt=0cda44af54d3 graphics=c1b2ccb71270 history=45387defc739 ansi=abe60f4d1602 ansi256=d6bc368e5286 html=524dc7f0d0a0
44+03/159 input=36e653d4e326 vt=88d69714c293 graphics=171fbbb1cccd history=233f4b0c2757 ansi=e2a055de3f87 ansi256=3a40282667b5 html=e8c71b93f771
45+03/179 input=abdc7322ccd7 vt=83b89bd0be8a graphics=c26da5657c11 history=f56741685971 ansi=d5ccdbca449a ansi256=dd0425640064 html=10c0b6c45bf6
46+03/199 input=70dc8e14e40d vt=368c5ce18628 graphics=d5de3993daba history=31647d60d27e ansi=39a12dd48435 ansi256=6b0c5ab24849 html=52ca4c678d86
47+03/219 input=19fb2dbf2b72 vt=5560f3c4e401 graphics=65eb029b7820 history=035984b53269 ansi=76e9d9396925 ansi256=fb130cac7f93 html=bbaf4c191a14
48+03/239 input=7c0c5314aeb3 vt=a0dfae216688 graphics=5c6b4ae18b60 history=16d405a75917 ansi=70a2961a921f ansi256=0d5cef42c7e7 html=7a9861f18818
49+04/019 input=ac95ee6bd1c4 vt=75730da64833 graphics=950dc65636f9 history=e3b0c44298fc ansi=1d40192d7f5e ansi256=7dd8c5f69449 html=a90d40d590c6
50+04/039 input=b16461f2d459 vt=89fde5beaa91 graphics=dff172a47e3b history=e3b0c44298fc ansi=189928fc25b8 ansi256=66a31fd27570 html=94c99c9a140f
51+04/059 input=3dbd041c8a93 vt=46c05b268911 graphics=e8b76a1b9359 history=e3b0c44298fc ansi=80563f330836 ansi256=dc1a4011688e html=aa6ca15fed94
52+04/079 input=6eb4f8e4532a vt=350a5e00a351 graphics=22f91ab97776 history=e3b0c44298fc ansi=0925fc7cb5c2 ansi256=45ee9ea10f8a html=fc626d1af828
53+04/099 input=db3717e615c0 vt=107edd2cc2a8 graphics=c34235f9e530 history=e3b0c44298fc ansi=af0374be4eda ansi256=151e18f23ddc html=74f0e0a24be3
54+04/119 input=cea55fc507f8 vt=b574c0bff677 graphics=93af9ac5666c history=e3b0c44298fc ansi=5add5259e40e ansi256=6138ac10783b html=6694d7af35ea
55+04/139 input=6955544376f2 vt=4f1f8af871a1 graphics=f538e5cd130e history=e3b0c44298fc ansi=f2c8d68bc14c ansi256=6c4c3b4fbd78 html=abb28b5beb15
56+04/159 input=b9a9ad2510b6 vt=8c8645285af7 graphics=3b4e5f278af3 history=e3b0c44298fc ansi=0b0a39ce76c3 ansi256=54414e73c0da html=879d40057ea7
57+04/179 input=211613aa2202 vt=c94fe03d96b5 graphics=d96a2ae371a5 history=e3b0c44298fc ansi=0adeddeaefc3 ansi256=9cc4ecb5bffe html=7cc5ca56a2d9
58+04/199 input=58e91ff2f4ab vt=6490ae61b95d graphics=d2752175246b history=e3b0c44298fc ansi=63f461c41790 ansi256=3c1d924c1e80 html=30611d9fd7f2
59+04/219 input=0eba9ec5a46c vt=1d18d28ac035 graphics=fc388d3d53a8 history=e3b0c44298fc ansi=680f2d93282c ansi256=2f45b31b9744 html=1ddfbe8755f7
60+04/239 input=e7f7c681f5b9 vt=0279ccd298ba graphics=81e51316a2a4 history=e3b0c44298fc ansi=7f4446d48723 ansi256=caa0483de38f html=c282e85e2abd
61+05/019 input=f708f21d5048 vt=41bb0068b9d5 graphics=54d51f156f82 history=07dd8ff61a7d ansi=72c3abe84900 ansi256=9d5c3edf7855 html=4a7b2ecf0e1e
62+05/039 input=85ab36e8b650 vt=efaa87c37a99 graphics=532ada5ceafc history=3f002ee29e52 ansi=17da07e9f85a ansi256=2e2edf5b0f11 html=28eb1294ac9c
63+05/059 input=2e2be67ca1d8 vt=2d832e81234a graphics=93c5f3db8810 history=26ad83f6ee57 ansi=49df0f3f3645 ansi256=f0b65aeb31f1 html=31cd90891c94
64+05/079 input=ba87d248dd45 vt=b4b08d9512f9 graphics=34b65f470628 history=9114e0fa08e7 ansi=09a785da16ea ansi256=194216597b68 html=89f907ea5f80
65+05/099 input=e10211359c74 vt=3ceccf69da23 graphics=dda37883cced history=73a01cd06763 ansi=850eda258fcf ansi256=5dd5fa36a9d2 html=b3c3b354c29e
66+05/119 input=fffb660dfb77 vt=4c267790e36d graphics=250e1fb7980e history=2f84702229a3 ansi=27896d56c106 ansi256=67417b228a96 html=baca43c0fded
67+05/139 input=11becbe9e073 vt=4896be991e3e graphics=b9946b6cbb9c history=d83501ac272e ansi=d665657c3a5b ansi256=f4e6bac4daf8 html=481b4b26e549
68+05/159 input=13ccb02683b9 vt=641ab8e1a9f5 graphics=fd8edc008758 history=1e949032c82f ansi=1c055d639abd ansi256=c39256b8bb32 html=9dc8479b34b6
69+05/179 input=391e22e966cb vt=1c6ed4e827b0 graphics=67ec83f5987e history=4c5309acfd04 ansi=133414fa03a3 ansi256=ac1eccd3b707 html=e4e11d09f7d3
70+05/199 input=7eb6729857bb vt=d7257566974a graphics=fe1fbdd5b0b4 history=4c0bd02293b1 ansi=4f242a4aca0c ansi256=a7c99d8be3da html=e7d40e2c3935
71+05/219 input=ba08f58d01d5 vt=1cd8cd975688 graphics=f59bb471eb52 history=534f3354524d ansi=b3db0423a107 ansi256=2188a64e0992 html=dc36d8842b27
72+05/239 input=366f9db6155b vt=b075af8eef2b graphics=89b9e8b5c474 history=c162856ede0d ansi=6ab7cf4895ed ansi256=40d312f0e070 html=92927bf6ba6e
73+06/019 input=74524b6e33c7 vt=48a669c6fac9 graphics=9258c91bf1d0 history=898655683e17 ansi=4713ac9daf80 ansi256=67a882e6ad82 html=b911dde00978
74+06/039 input=65197226e07a vt=f6995273dbeb graphics=ec94ae6cc7b9 history=5362c829d6ad ansi=2e6a4fe4092e ansi256=cab88d1949fa html=e2ee10938c01
75+06/059 input=0059c87f2ba3 vt=aa1cd4936ce4 graphics=fa4b1bdcb736 history=8d74567c7596 ansi=47ddcf9ea936 ansi256=3cf60f5f6c0b html=76ba5fdb95de
76+06/079 input=d1e20fd8eb50 vt=9ec6d176dcc8 graphics=8183b528dbca history=4d405f4fb2ca ansi=9659e34e0243 ansi256=0edab42116ad html=2b36d393a76c
77+06/099 input=cafcb126860a vt=5afe741a2678 graphics=fac73a1bb510 history=13c0d17ff5bd ansi=f55dd08f48f4 ansi256=e644288fb538 html=685b92a736a2
78+06/119 input=a80f65f5b0a8 vt=ee42a12d024e graphics=97f45805af9a history=967e9dfc2073 ansi=cd0494e91242 ansi256=1d6db9d74155 html=ecd2b64c1487
79+06/139 input=62d38f2be4a0 vt=238cb53ef640 graphics=f9e4dbc600c0 history=1a9c7f633db0 ansi=ef51adddf2f0 ansi256=7e7e85043c92 html=18ed59e5f344
80+06/159 input=1cb1815e815b vt=831a04bbada5 graphics=7bd60ce8809b history=716ecc549fb4 ansi=97b20d9d7b63 ansi256=f9473ebaf756 html=8bdb2b2c8d25
81+06/179 input=5badf3d2dff5 vt=c620f20feba4 graphics=1698c6765d18 history=f4624d43f8fe ansi=394a6010d7c3 ansi256=c0412c491438 html=aa3ec816effd
82+06/199 input=d3d3d2ce734a vt=28cd61f9633f graphics=09f725b24161 history=3807f05bc93c ansi=bfef2232dc63 ansi256=023386bab8cb html=1af233b18eaf
83+06/219 input=8506dd47df97 vt=b148edd65135 graphics=19818e5dfbce history=cef46ab3f84f ansi=673db820b25a ansi256=912deffb9972 html=d56e75c605ef
84+06/239 input=077726566d29 vt=064f0e868a78 graphics=cd062ea3471e history=3b8a6b0106d8 ansi=506bf9a5f620 ansi256=80c6f5141a3f html=d9fa0212e304
85+07/019 input=fae29ee9e551 vt=4d8363b27bf0 graphics=e93052db1f72 history=a016741d0c17 ansi=fb6cbbd2bbb1 ansi256=b6407309d580 html=1904c198bc6e
86+07/039 input=dc25e2be6a38 vt=f0b1efcfcfa2 graphics=50e4979362e6 history=493077d95eaa ansi=fe6fa23f8ed3 ansi256=a10d6bbfa9cc html=59e4d2e00aa9
87+07/059 input=7975bd5ebcd1 vt=fac6dce4c0d8 graphics=57703a717cd1 history=3f97ffdc2dec ansi=25965c7ad385 ansi256=3da98bce60a1 html=b648e177f0b2
88+07/079 input=9c6219207676 vt=c94ffbffb325 graphics=fc80a80a4994 history=c02df921f9d1 ansi=a5d71cafb48f ansi256=3c6df957f87f html=2bf30738dbc6
89+07/099 input=92186125c91e vt=9e6e590d719c graphics=b9fe79beddae history=3f28dfa7b563 ansi=95707765409a ansi256=1bdc74a4465d html=f33078e2cc8b
90+07/119 input=8fd98cda3883 vt=1fbec962753f graphics=c37f447943f5 history=0d80f172198d ansi=f55cac729412 ansi256=bbc080afd759 html=2f9227221148
91+07/139 input=388a492ea7fe vt=bb6eefe94a6f graphics=5ad6c9e6e516 history=044cb3ac10ba ansi=0ffee86f12c9 ansi256=12f550934278 html=df8750ee768e
92+07/159 input=2d0089ab5f6a vt=034e8c8d8411 graphics=109355c3ac63 history=c359ce2d2381 ansi=4111ff4d3cda ansi256=16385f645c5e html=fe6a2200015c
93+07/179 input=9e4cb64f8a8c vt=1e5650773386 graphics=9a017a89f0dc history=591f5b1ff1ae ansi=b2cda00f5d7b ansi256=f31f5aedab35 html=653e213032d1
94+07/199 input=4353da204940 vt=f3b87f13eb10 graphics=71f7c96bfdae history=50ee391fa45a ansi=21971bfbc100 ansi256=e9ebfde84853 html=ad6f2f4f0ec1
95+07/219 input=dbf5ec27883f vt=69598cc4d0e7 graphics=710c0213a1fe history=d693455d4f7e ansi=53c3b90f9274 ansi256=8a2a3ca793cd html=9ee083a32da9
96+07/239 input=ee738b75ee7b vt=e8eb1c81e3f2 graphics=c9d2c2dc189f history=3064233b1b2c ansi=2da069a3b0ab ansi256=2652868cc89a html=70fad90a28fb
97+08/019 input=ffb611ad4389 vt=e72fb0e18d1b graphics=0af58323e07f history=e3b0c44298fc ansi=eba47ed76a95 ansi256=61978201c3de html=c5f7b46ad24c
98+08/039 input=cec6bf13be3c vt=3515ec5c5c8c graphics=b5ac885200ab history=e3b0c44298fc ansi=efc869104b50 ansi256=3c21d039ec78 html=ad915c491c57
99+08/059 input=687fc086986c vt=f60a863259ce graphics=dae0356b61d7 history=e3b0c44298fc ansi=135df0896a7e ansi256=7b605cee5329 html=8d3fb3996cc3
100+08/079 input=26b30a7bfe76 vt=3c80b0ac0d77 graphics=7ab6e8e4205d history=e3b0c44298fc ansi=9ffdabb3d74e ansi256=384c10e114b0 html=db675520568c
101+08/099 input=85d377028faa vt=7258eb053a31 graphics=1b7d1f50bca5 history=e3b0c44298fc ansi=0f3c263fb26d ansi256=6302751823d5 html=59317cd039d6
102+08/119 input=721048e0006f vt=8c18883d7799 graphics=933354e913ef history=e3b0c44298fc ansi=80e418ed9332 ansi256=6f9633182d67 html=5878d788176d
103+08/139 input=e89bacfc0b2a vt=2175ffd19d2d graphics=76585c8b0c85 history=e3b0c44298fc ansi=444b4cff6b95 ansi256=caf0f0407661 html=3adc8b865793
104+08/159 input=6bcd5944fc82 vt=3f8142208b56 graphics=ac884b93caf7 history=e3b0c44298fc ansi=887116ca8f6e ansi256=b317af8348e6 html=29d4019bb2d8
105+08/179 input=5c4c5729bd97 vt=af526eeb4ae5 graphics=223826b2fa2e history=e3b0c44298fc ansi=8d1309edf72a ansi256=f1a71a58ee69 html=2ffd35213559
106+08/199 input=219d070f7cd5 vt=ff2bfd155de5 graphics=edb68bafb771 history=e3b0c44298fc ansi=3b50eb64330d ansi256=624d1973d4c1 html=fae82782f004
107+08/219 input=9a8b9ab14cf8 vt=6e6f6c767761 graphics=1d9ff4825974 history=e3b0c44298fc ansi=a02880b1f6d8 ansi256=2d8685209b13 html=7c47212ef248
108+08/239 input=d5a0eabb673d vt=59a1e70c0ae1 graphics=7c4d6749fdab history=e3b0c44298fc ansi=ee7fc1249130 ansi256=827ebce60d16 html=60e96934c1e7
109+09/019 input=375c31d38e01 vt=e61ab6ec4c87 graphics=9258c91bf1d0 history=ae793708b2e3 ansi=9933eb508d02 ansi256=825a3a7b06cc html=dc8dc5491115
110+09/039 input=51adeda97c8a vt=8538ff184ac7 graphics=ec94ae6cc7b9 history=3355696a7a17 ansi=8d7ca8687c2b ansi256=8104cf283c3f html=05130e0da4ad
111+09/059 input=26704fddad28 vt=784b54585b46 graphics=04ecffba52a2 history=398a3fca14d9 ansi=7ffb8815309d ansi256=1e5a60233787 html=4a85047ed01c
112+09/079 input=a2c65542686b vt=95266b5f896f graphics=429dd0371fdc history=74dbda994020 ansi=5412731ac28c ansi256=626afcad4b76 html=f5f8ef6ba658
113+09/099 input=63f82eef3142 vt=e1628289d678 graphics=b012cf49350e history=e653fd8f57b2 ansi=1990868a0a83 ansi256=154cb27c6867 html=8720031f8dc1
114+09/119 input=50f417492a89 vt=95ccdf0c4556 graphics=3c082a76bd09 history=eca74c726b29 ansi=25f847e9a0a1 ansi256=8bbc1364711b html=3110d4191b15
115+09/139 input=f22701044a4e vt=7228dceef0d8 graphics=5016c8d979ca history=555cc174c81c ansi=d92b9305a595 ansi256=ec316e005b62 html=de0e7c44ca73
116+09/159 input=f4cde1fc68a6 vt=ca04021ddae7 graphics=44017697e035 history=b51ca289a2cd ansi=3537fc95a66f ansi256=bd90418c5f00 html=6ae5b29a5d33
117+09/179 input=fb22f401fa59 vt=700c026a33bc graphics=889a00c22cfb history=f07dc27c1831 ansi=ab274c4be5dd ansi256=495917d23e1b html=d3f3e23f5d84
118+09/199 input=9ebd3391a785 vt=3693180d540a graphics=8441eff04541 history=9f926ff96f78 ansi=4a7c3681294d ansi256=f9b30e3b20cb html=f82cf6f343ae
119+09/219 input=7c79ac16673d vt=b9a4c0603935 graphics=a83ab7751bc5 history=a03bc237d484 ansi=48dc26e77ed3 ansi256=040865fea0e2 html=3b2fb2e87e14
120+09/239 input=33d1b8f46fc6 vt=5bf2f76601b2 graphics=d4f2f55f7ecc history=105ae31c67f2 ansi=c4ad351e161e ansi256=8ed3feb18879 html=c609fd52d6c6
121+10/019 input=4a773fa88d0e vt=e56acbaa3c3c graphics=f8979b697ae6 history=9a1d180260d9 ansi=b2b0a3acf112 ansi256=e99773dd4ed9 html=c3b1d6f9af79
122+10/039 input=5a19d9d4c2d6 vt=7ffdb9e95420 graphics=896174966c8e history=091b178e1831 ansi=7d1e36e89a84 ansi256=e415fef4821c html=952d3c5bf21b
123+10/059 input=3d61fb352e87 vt=156ac33a85b0 graphics=60644c95d91b history=06f1f1fab2f4 ansi=a2d1a144f34a ansi256=6e2066d8c58b html=1a1175166ea9
124+10/079 input=d5182a61be8c vt=cd5fdb02e924 graphics=309679508d19 history=5fa6d8aeda89 ansi=2a0e3196bfd6 ansi256=9e1147ef50bd html=ce8dea3d316e
125+10/099 input=66f393c8e024 vt=2e7994bde84b graphics=dbc14a5ae241 history=04998276902f ansi=aee487949558 ansi256=c87b7581c162 html=619c397c3d0f
126+10/119 input=b49c6e9c2784 vt=c46e5f7f618b graphics=33cd5cd651da history=5c9911da4a8f ansi=6084136b1e33 ansi256=a33ff57d23c0 html=51a347687195
127+10/139 input=b1b06a0b58cd vt=b88fda26708b graphics=b9cd90b1ed9d history=41f382e35a07 ansi=01c25d2d4537 ansi256=9d617a7f0a07 html=5b2119c988ff
128+10/159 input=fbaf8971741d vt=19ec261f5b77 graphics=bcf25cdb2e51 history=c5cfe985bd1b ansi=4ae61c21451f ansi256=9c3dc8f71556 html=99d1313114bb
129+10/179 input=b02f77b5cd73 vt=5375dd4ed7f6 graphics=f591bfded96c history=c4fcf5031cbb ansi=500ee209d80a ansi256=ce2b80daad73 html=dbfc1a9f8389
130+10/199 input=cc1128412f8b vt=7e4d2086c5bb graphics=b4956c877d8c history=a2b67591b711 ansi=00bd358eb62d ansi256=f141b4f09b2d html=b15c9bf82493
131+10/219 input=2347ed53f13f vt=0af90759155f graphics=b19cc5de1ed4 history=88d94c1e29e9 ansi=ad17609946ad ansi256=737472c30aeb html=ff561dca927b
132+10/239 input=8a8aa55dce6b vt=7a75f8f03acb graphics=b5618c41bc19 history=5d74197f29fc ansi=e33bf0b866fd ansi256=43b6ad691359 html=2c6a65d1b030
133+11/019 input=9265dacd75c2 vt=375101271ee1 graphics=f8979b697ae6 history=711a38708632 ansi=84ce9b2e5448 ansi256=f7d6444a0ec2 html=685d54b5cb53
134+11/039 input=fa84608e0849 vt=2a74efb6ab39 graphics=5dbcfed44856 history=e862c7fa8409 ansi=0497214221c4 ansi256=329e82145d64 html=d523431dbaa8
135+11/059 input=55f99f6d98ed vt=2a5bd217b354 graphics=7cc33ba32eea history=f6afc9616658 ansi=23f55173e472 ansi256=e8d2f6e6ed2b html=e82979905278
136+11/079 input=a9b3a0df8858 vt=7d9930235196 graphics=6919c4d26b60 history=c5fe90406ec8 ansi=829d8d678f5a ansi256=000d15ca2660 html=1664c0bc58b7
137+11/099 input=ae76386fd7d1 vt=9cd4bda7b6f5 graphics=d455141d92f7 history=ead2e3f30d49 ansi=82a2bb0a9bdb ansi256=91509db5578f html=8618f8ac0481
138+11/119 input=9af26788e7bc vt=a3c03f3376e8 graphics=15a3c905b21d history=481784c95062 ansi=bb43cb4d0950 ansi256=f2f5c846ddf5 html=a780738715d5
139+11/139 input=f9baf0d2fb38 vt=ab6a31624261 graphics=a221841874c6 history=4248d3856c10 ansi=46d0c42a80c6 ansi256=0e32105ecd9e html=e9c94b0050bc
140+11/159 input=95a95c43643e vt=d046ac47c2f6 graphics=d4f6f0ba7eb7 history=1fc26a2b22ca ansi=56ab2524964e ansi256=ad04371dbbc8 html=fc00ae7bffeb
141+11/179 input=dcc8364da3f4 vt=2129ba5cc2d2 graphics=f865953d3b1d history=598bb57229f6 ansi=adca037af52b ansi256=47bfdd0b6b2b html=52341cfdd5cb
142+11/199 input=203eef9c539c vt=d90f5a5f35fa graphics=cb2ad40dabec history=a23d1435d01d ansi=1f57d064d798 ansi256=7175de8c5a24 html=4ef9a65aef53
143+11/219 input=32e59dd96f51 vt=66a86a72207f graphics=d19ae5484f1b history=a0c79bc4d577 ansi=124273bc600c ansi256=0eaeecc77e90 html=2d84f0b34b02
144+11/239 input=9fa7f4fdcde3 vt=7a764cea4e94 graphics=1ac611e08f86 history=793108a49d50 ansi=dc3e80fe3499 ansi256=4bfe0f0735c4 html=d53adab71625
145+12/019 input=0cd53f8dc866 vt=94283af4d7bd graphics=aa1966378332 history=e3b0c44298fc ansi=9635b13597ab ansi256=9020c0176325 html=b2744def1bed
146+12/039 input=a4adb8bd74ff vt=1e4fa3c28868 graphics=446b136e5620 history=e3b0c44298fc ansi=846ae78c61c0 ansi256=61463b656f85 html=c3fe542cf614
147+12/059 input=8e1743411c94 vt=f2e40d527f1f graphics=383509aa2748 history=e3b0c44298fc ansi=e43feca44dd4 ansi256=5592050ecb33 html=ba5853607654
148+12/079 input=24b7b3927733 vt=ca5d80c350c7 graphics=adb60fbc77df history=e3b0c44298fc ansi=54cf7d6a19d2 ansi256=e8bc1048d1cb html=8720cb8d4748
149+12/099 input=084e6637aff7 vt=5364ef66f04e graphics=8aee9666cf7e history=e3b0c44298fc ansi=3c9190df845e ansi256=df24c0122682 html=43f2d2763a3d
150+12/119 input=dfad7236783e vt=b47b5f66a92f graphics=fc1ca2755ec5 history=e3b0c44298fc ansi=28f7789859cb ansi256=bfe43afcf74c html=7a25e8488c73
151+12/139 input=868d9b85b00d vt=b35476bcaf77 graphics=71e72390b15a history=e3b0c44298fc ansi=7a113a99cba4 ansi256=154812340ca6 html=bdbe756ad0eb
152+12/159 input=079a8d8cf303 vt=d5c21fc98ebd graphics=8e59b761a886 history=e3b0c44298fc ansi=633f2c29a069 ansi256=0a5d8a4bf2cc html=b5de688f4e37
153+12/179 input=b04504a5e95e vt=dc59f7f4f179 graphics=0c74926a3adc history=e3b0c44298fc ansi=6616cc37f757 ansi256=8bc4de6a188b html=729d8e8ed02c
154+12/199 input=087381b37012 vt=2dfb9fe9cb33 graphics=fb30a203819e history=e3b0c44298fc ansi=0ab48534e4f0 ansi256=376f1c085a06 html=80424fa73a56
155+12/219 input=1c3f8730674c vt=af87d933c49b graphics=28a7ba5996a9 history=e3b0c44298fc ansi=2c88572f8243 ansi256=50eb8105b067 html=618f932e30bb
156+12/239 input=01426d60b04b vt=b39a82a17c4c graphics=3a167d043f4a history=e3b0c44298fc ansi=e63cf3dfdbc2 ansi256=e5a6efa00e87 html=1a1101a850a3
157+13/019 input=7520f8daaf0c vt=acafc9adc02c graphics=f6ba63ec3717 history=46adc8d8dbc3 ansi=a96cee0c7c56 ansi256=1ff37de7ca5a html=461dbdd7849b
158+13/039 input=0b6c937d49bb vt=f0da4cf5bffe graphics=80775244c49f history=a68772b5b2a4 ansi=a605a2ddaaa4 ansi256=6c548f01ade8 html=2be43a85cc1d
159+13/059 input=73c036bb83ab vt=cccfcabc9883 graphics=e654e9345138 history=fe83f6679c59 ansi=dec1eee5f6b7 ansi256=46df57dbc15f html=f2bd74cccefa
160+13/079 input=1740e9668bd9 vt=2af93a316eea graphics=3c8abf2d09db history=59798eb0f0c0 ansi=c3f28ae5b5c4 ansi256=e17cc886a56c html=86e264ad48ff
161+13/099 input=8bee21358f91 vt=e5a61a289e0a graphics=3bf53336708e history=92cf7dbf6937 ansi=3162b5f25c5f ansi256=f762ea238db0 html=95aa64fdd24b
162+13/119 input=4a7587dd0528 vt=a42eceae253a graphics=f3248511fb51 history=43d954a57008 ansi=22700a2fb762 ansi256=ab2e8af6974c html=33a564524571
163+13/139 input=a013d2d99b71 vt=c56c6570ce4d graphics=56cf16bd1b92 history=2ed23713a723 ansi=09aebb4d1635 ansi256=1c5bb54127d9 html=36c58cdf4992
164+13/159 input=671dfaa83917 vt=d53289c06948 graphics=d145457d4b59 history=80fa71b1a3aa ansi=d40af80aa84d ansi256=b5417d3c6341 html=e37a3eccd6ce
165+13/179 input=4ac1c3073a32 vt=8dc458197d00 graphics=e8ea9c343f0d history=7d8a9ea0b656 ansi=64beed089e47 ansi256=1808932f9729 html=f4affc600b08
166+13/199 input=8db1eaec3f54 vt=5c71eaa36a21 graphics=c27ebde9c961 history=b19a73a76ecf ansi=b8592ddd4d3b ansi256=00729536519a html=39aa8e2fbb44
167+13/219 input=9fb709c6f4f5 vt=5887f955f492 graphics=f81762265c3c history=ebf71b617ff3 ansi=580afcb45172 ansi256=ae3d6515c35b html=5cd3d7c38131
168+13/239 input=607893ccc66e vt=9b45c6f4ad16 graphics=57aad1c476be history=7525380830a1 ansi=34ebc3bbd92c ansi256=0403d973c622 html=60dae1c93eeb
169+14/019 input=a7f334c12c30 vt=9bcdf21a28d1 graphics=81c725928397 history=2385a3e8dab8 ansi=c0c9f7a64341 ansi256=b31486c31b86 html=35708e80da60
170+14/039 input=cb163ae3c433 vt=5753f4daeff1 graphics=d7c6ebd7cfc0 history=587cae73034f ansi=2d4925a35af4 ansi256=f66845c5742b html=baeb6bcefb51
171+14/059 input=f56d76937fd0 vt=57b2f629970a graphics=8a7d860c2c19 history=2fbcda1cb486 ansi=c6cb6b834b4e ansi256=845612b63a58 html=9252e3a88f4c
172+14/079 input=f33604d23f28 vt=c974e326a90b graphics=6f6c28b5e14f history=9c6e93bf5ae0 ansi=a264f3287c53 ansi256=aa0e7995674c html=678f55e2b870
173+14/099 input=66e2c12b7a2c vt=21ae28e601f7 graphics=c841084c011b history=77fcecaf9198 ansi=f88e07c8b8e7 ansi256=f61593ae5173 html=b615aa206946
174+14/119 input=2423dd867693 vt=260dca79f790 graphics=13c1d848ef7c history=0578cc790f11 ansi=d6cd6e0d3a39 ansi256=a7030caa2248 html=0248bc83fd1f
175+14/139 input=6bba00dd2011 vt=a272f823ab24 graphics=ff9f2a7413a2 history=e88c4115b82b ansi=219f25d864eb ansi256=a895895e4810 html=3f8fc72b3e73
176+14/159 input=bd6974df946a vt=04ddc0b7cc5a graphics=d0cc3cf7f292 history=115133c655d6 ansi=f5a8ffdb271b ansi256=18c35ff238cd html=b9c2a5885b26
177+14/179 input=37e67a5d9bbb vt=0fde96b6035a graphics=d7a2abfae087 history=e67566a79d14 ansi=527202ca46b4 ansi256=8a82a2201ac1 html=39eb2a61fe24
178+14/199 input=e37a2b467fbe vt=b24e698bc457 graphics=b8031e6234b1 history=6c6cd77efa68 ansi=bb95fe893d2c ansi256=b167c3b0e86e html=5ba24470430a
179+14/219 input=1029130bfbb3 vt=e88b9860fbf3 graphics=334fcad630b4 history=601f1eaad212 ansi=34f9eee0f681 ansi256=a7a0e8e22cf3 html=e8f97d2a8ab8
180+14/239 input=4f4b33115d02 vt=665ba03c5b8d graphics=bcdf3ceb7d32 history=64972943269c ansi=abf6d0a0365e ansi256=568e79b90695 html=b26a8767b60f
181+15/019 input=adebbbf2b67e vt=592cebb0eae3 graphics=9258c91bf1d0 history=9f7f72048c7e ansi=a847879b9e08 ansi256=7289d4ca24b0 html=c81ae1f026d5
182+15/039 input=2f24c044f13b vt=9b88bb5525f8 graphics=7273f3c7ea47 history=10b4c3487308 ansi=d813c264ae04 ansi256=513731bb2435 html=832e48b619ef
183+15/059 input=3f7f0171fcbc vt=f9c33f6d70ca graphics=65b90ea66aa7 history=61984d2b07f3 ansi=11c2dc4fbbdd ansi256=a295c8d95c3d html=74a231c8abae
184+15/079 input=73c002f7f158 vt=24e15581eb38 graphics=3cb55010354a history=d1eb9f880a9f ansi=26e7212c03ac ansi256=1c68f8acd6ac html=d6b96f3a1124
185+15/099 input=d0d48ac2b495 vt=9a76e08324cd graphics=ed4caac777f5 history=0c0c27929ec9 ansi=82c96808d0b9 ansi256=f675fc6e8262 html=73ffc8cb16bc
186+15/119 input=3fa81ee4d3ba vt=a81be1aa206e graphics=ff117fead386 history=20d00a7e251f ansi=3aba1781bad7 ansi256=07e4c09ffdb7 html=6dd9ca74de99
187+15/139 input=68408fbbf5ee vt=a32e7bbf0c27 graphics=0054f2fa69dc history=580f23cdf9fd ansi=ac525261d78b ansi256=b10a40001689 html=8959a3ae5b86
188+15/159 input=ba1363213435 vt=3619f3845be9 graphics=78ed8fc1091e history=b7aa7e1d1cad ansi=28499c397587 ansi256=89ad14bc135b html=1d2ae39f6ea4
189+15/179 input=33e641fc5d55 vt=f64b9094c4dd graphics=ef3c8c1e57a0 history=186362c6d3a3 ansi=4b9d9655854c ansi256=a1c9511e4cd2 html=cdc0d8cd4e2c
190+15/199 input=ef88153e80d9 vt=0801d3286cdd graphics=2d4906246230 history=fd3b0095a05e ansi=00e0730b7f8f ansi256=4324a4e945bd html=504e8fdfd696
191+15/219 input=fddb2208db96 vt=1369dc45a440 graphics=b012b26b3b66 history=2febb7f5b494 ansi=1413b3804af6 ansi256=c0d3e8b8786e html=cfb271a64a93
192+15/239 input=6a6b1380bfa1 vt=0ae81863dd42 graphics=701820e5764c history=4f15a73b2b68 ansi=303f8cd3cc58 ansi256=520deee2c650 html=c16b2ad7d817
193+16/019 input=86c2dda4db03 vt=6d7415e4ab74 graphics=f8979b697ae6 history=e3b0c44298fc ansi=76a6fbc5b6c3 ansi256=ff3164ac5487 html=12bb8014b393
194+16/039 input=55ed57bbec1d vt=c7de0211b8a3 graphics=982379a6cc3d history=e3b0c44298fc ansi=0a5c39595e6e ansi256=d0cb3aa4a078 html=882f254a57bd
195+16/059 input=75c0a5c47c7c vt=41df5e7c69c2 graphics=842a2ffbda7d history=e3b0c44298fc ansi=7e4f99dcb027 ansi256=c9183d6491e2 html=aaed4ccf4e11
196+16/079 input=e47d941b4795 vt=29818752a1ca graphics=83bad9ddc481 history=e3b0c44298fc ansi=1c402472c1c7 ansi256=0b8c9fbd2c3c html=da5f12987565
197+16/099 input=1d5b3f836ac9 vt=fa20f6be77fc graphics=a76562326d86 history=e3b0c44298fc ansi=56aac95f1834 ansi256=fe63446dcca4 html=9ba9d95cc8dc
198+16/119 input=3732e6080846 vt=79f64e3b5554 graphics=14f68a7bb6bb history=e3b0c44298fc ansi=cb0bb8b4fadc ansi256=afa479443df7 html=74a9930b54de
199+16/139 input=1c79946f3ea3 vt=c45bb228fa62 graphics=2403dce32ba9 history=e3b0c44298fc ansi=1ca0a48540d9 ansi256=1096ad83e268 html=53c873c508f3
200+16/159 input=b2687f8c50d3 vt=1501b13122dc graphics=3c87413b9ae6 history=e3b0c44298fc ansi=34725ee3e966 ansi256=f85d124e4f37 html=cb92bc348ac7
201+16/179 input=e6f371d2288b vt=f22a83e34a23 graphics=1d16a3c1ae70 history=e3b0c44298fc ansi=1e5b0b8d3682 ansi256=a80b1cb97d9e html=6ed1d0943b74
202+16/199 input=ef6ef7381c1f vt=e6c36ee8cb16 graphics=629add49f562 history=e3b0c44298fc ansi=d8e1c77f2871 ansi256=5118043a76e9 html=182382bf5aa1
203+16/219 input=a70b8d880419 vt=f6f6b6285356 graphics=379bd66ce1f5 history=e3b0c44298fc ansi=c9a98c855aba ansi256=548576b0b5cf html=c1ecafe6cceb
204+16/239 input=e318eee4b6f3 vt=39841be2f7a7 graphics=d1fb1b1764e1 history=e3b0c44298fc ansi=d33af6657153 ansi256=a292cd0f0bc3 html=9f12c4a9c576
205+17/019 input=58c9a4153140 vt=324b438d3711 graphics=f8979b697ae6 history=711a38708632 ansi=5c9302e7cb6b ansi256=85a7583c5c6c html=d1cd396bd85c
206+17/039 input=db579e65ea7d vt=6fbfe2c1e929 graphics=5dbcfed44856 history=90f1132b4c8b ansi=d33d277dddb9 ansi256=877081d93305 html=bf1412d87fde
207+17/059 input=f1499c3938fb vt=eed0360845e2 graphics=e7bc26dbbc26 history=c11561ff594b ansi=fe2e1e877cac ansi256=d77c223b95c9 html=91f0252e84a3
208+17/079 input=9ec0bad9b8da vt=854ea5835b4c graphics=4e43c7db5d2b history=86f74a48ec8e ansi=233882d7d87d ansi256=b333d4c639b3 html=87008431833b
209+17/099 input=b1a45d5c094d vt=fb72368bcf60 graphics=7b45a01a7c43 history=864baf9e2a68 ansi=c5171a082201 ansi256=19ce8af4292d html=808649c8f7b1
210+17/119 input=630c816a56f6 vt=7f3660b85dac graphics=5b2757212ce6 history=b1f20dbcbf8a ansi=137fbfd28076 ansi256=13c827cb60a9 html=c67aad58b8ae
211+17/139 input=22d78f18ce2e vt=ab7b75a6d8f9 graphics=b437e11b41ee history=ad9bf3567e67 ansi=4b9c15d40677 ansi256=cc3881dfbffd html=8e9e0016dcd7
212+17/159 input=4ef271e495f0 vt=d00fe585dc54 graphics=6fc51315d33b history=d0783031468e ansi=e2224565fe65 ansi256=45f3942d9b49 html=b07e484d1f80
213+17/179 input=e9b418a8b2ef vt=24199de84f03 graphics=a0cfd961aa4e history=4557d790c7b4 ansi=fba711ad72c5 ansi256=a9694cf6a10c html=ddb0554e57d4
214+17/199 input=61ca70a2bf80 vt=b1839e18ae6f graphics=92f8577c9b42 history=b81d21bcc4d5 ansi=6c5c1bb9cad5 ansi256=406444ebbca7 html=c85efa4f3290
215+17/219 input=ff5c94c9b013 vt=5d22d9894727 graphics=7bc5dede1a89 history=4b4ab2d37875 ansi=dc67081dc05a ansi256=95c664bbd051 html=3a1923f73eb1
216+17/239 input=8cb41999a222 vt=dc320c39f15c graphics=7de85cd30f7a history=f0da9faa34f7 ansi=b53f7cb0427d ansi256=23ef37e00200 html=43d304aed60e
217+18/019 input=1a8fb352acf4 vt=8c78c5a6e699 graphics=f8979b697ae6 history=cd2c313ff542 ansi=2a1160b2c9ef ansi256=8c5b08c915f6 html=2bf2911efe68
218+18/039 input=120fd08d580e vt=9d25a6b19337 graphics=896174966c8e history=875839281971 ansi=e78d4972dd5f ansi256=93a1db68bce5 html=3175a85eb9b3
219+18/059 input=82098b093bfc vt=6c75370c7db9 graphics=207a60bb91d0 history=24174fce0b1f ansi=66d2d608a1f1 ansi256=158b0e0a39ec html=7dd3e682b17a
220+18/079 input=cbeb78d372be vt=d27386b7d77b graphics=7de8d4796cb6 history=59795806ccc0 ansi=03e7a153c2ee ansi256=0b42ab8e910c html=089bcb7a902c
221+18/099 input=fe6eb5467cf1 vt=0784720cea47 graphics=e25a6167d75f history=1d9cfd1abb4e ansi=75bbd8201a08 ansi256=a34e0ca1feb4 html=f63a6dc3a8dd
222+18/119 input=95f0f611f332 vt=d017ed80bcab graphics=2049bdbbab3e history=a63d9aeb1f01 ansi=94ba30222542 ansi256=aa123dff5919 html=9ef446e144ba
223+18/139 input=3c2f99ffc023 vt=75e8e55898a9 graphics=f0595f3aa950 history=9d638c447b01 ansi=fa31decdd13e ansi256=6b7d5c6d8d68 html=d72827d09492
224+18/159 input=9ad591a6fb7d vt=4269793feb5b graphics=310714a28461 history=4758ee28b6bd ansi=91e9125972f8 ansi256=797e0afe0aee html=2319778b4656
225+18/179 input=4cb34afc6104 vt=0485fb01b5dc graphics=145af612aaae history=e3bf8800fc5b ansi=ac0b90d29af0 ansi256=6f5f308aa309 html=3ac541d9babc
226+18/199 input=30c450be5b97 vt=13406cc1f87e graphics=de90792e0729 history=241a96bae4c7 ansi=fb45d99a1b40 ansi256=a895d173ea7c html=169bf57f5be4
227+18/219 input=98e3ba6d672b vt=5786a38e5eca graphics=d73ed6f6b01f history=679dde0ae545 ansi=45503c8e4ceb ansi256=5e823b3c23fe html=da83ebd9c28b
228+18/239 input=4cdc68b810b1 vt=11f8526bd447 graphics=c934b313196f history=5f8e6cd1474f ansi=a4e37289b509 ansi256=d17b781bf646 html=d9facf5ef080
229+19/019 input=f025072611f9 vt=98568b096752 graphics=ceeffa9ccef0 history=223962168d6a ansi=982272b5b3fe ansi256=e8fa54fc8107 html=b4c79949091a
230+19/039 input=a0fb77925963 vt=bc9062ea2ed5 graphics=6bbb371766da history=b4f46e999dc1 ansi=5ea1a0292697 ansi256=2945a8344189 html=67aa33fe168e
231+19/059 input=3143a584229f vt=5cfca7c8b962 graphics=a0f8cb27ebae history=bb35f1365c5c ansi=7fe21ad4ea22 ansi256=8c0a1fe0ff92 html=38ad5252ae40
232+19/079 input=4d3dff9e2a08 vt=98bf07c97ece graphics=00fce6dcd131 history=a677db84e2e6 ansi=14ec6eb04e0c ansi256=3ae2236e1d07 html=d2988f43f0b6
233+19/099 input=a19d75d8d10d vt=650ec28e93e2 graphics=59ddaa7408c9 history=9d586b3ecfa3 ansi=87ba403a3b61 ansi256=14bb2fab1628 html=10230866f668
234+19/119 input=dfd4382938c3 vt=800f59356c9d graphics=4e3403b66904 history=4a12e0d293d7 ansi=c06123578fca ansi256=14e2b9939b37 html=2063bd042d4c
235+19/139 input=d9daa2a5883f vt=4da1fe870181 graphics=b6b22e3b11c4 history=fc9604300c0f ansi=b45b6aaefb3c ansi256=3763b0de69f2 html=9fb9f7ad76a3
236+19/159 input=45fee457c34d vt=c150ddb3ac4e graphics=49f24bd1c839 history=996c5b447767 ansi=dbab6aaa9d86 ansi256=c3a8bee718ab html=f9c6e7a7791d
237+19/179 input=3f763216e7cd vt=ea4eb51b5f00 graphics=fe3c10d6141b history=d4d85159b904 ansi=01a5e9d16446 ansi256=dcae4df49cdd html=3fd07b41ddc0
238+19/199 input=16fa624597c7 vt=c9df47e68a7c graphics=9dd86c09229e history=5142585fde71 ansi=f98e9a365f26 ansi256=89d119043450 html=e95640b13639
239+19/219 input=5db9cbb2203d vt=6af15b8cec32 graphics=bc944b4862e6 history=9553e7f99699 ansi=2554dbc19ef5 ansi256=f147b4cad322 html=b03435926fa9
240+19/239 input=ff65425ea000 vt=14e5cf5f064a graphics=786652c8dcaa history=93b9446a5724 ansi=3e8b96b5b855 ansi256=c35e2ebba309 html=711b0093e774
241+20/019 input=16ab1b41f873 vt=1499bc214fc5 graphics=9258c91bf1d0 history=e3b0c44298fc ansi=6e012cb0dccf ansi256=da37e6c9d339 html=1e5a56704b1f
242+20/039 input=7fdb1cd71af0 vt=b0db232b4e0c graphics=ec94ae6cc7b9 history=e3b0c44298fc ansi=3119d279d44b ansi256=53b0a1780247 html=52d553f534aa
243+20/059 input=97bbd10bdc02 vt=4072b59cc2ed graphics=7bdd0ed29a7a history=e3b0c44298fc ansi=fe617dc64f1d ansi256=a5be42706dca html=f89b539d3cf2
244+20/079 input=4643c53e7d5f vt=258eb8d27202 graphics=484b3575b9e4 history=e3b0c44298fc ansi=b58678e2d51e ansi256=f1a4cbf04a19 html=c0ec4c442871
245+20/099 input=5c6ba398d86c vt=b3e2901f9ce0 graphics=3a68ef622ce1 history=e3b0c44298fc ansi=24622d01be50 ansi256=453ef09e3e72 html=09a56a97c1df
246+20/119 input=bf82e477a33c vt=127461ab7faa graphics=dc64f3a0bcf8 history=e3b0c44298fc ansi=811ab8b1df46 ansi256=1fc38e82a4a2 html=69239da06710
247+20/139 input=4713957fa737 vt=25e0887161c7 graphics=3bcd0d1750d2 history=e3b0c44298fc ansi=0e872d556857 ansi256=2f37f4d66894 html=ea55b56c71d7
248+20/159 input=4ae9c4eeb18a vt=709bfec3b6fc graphics=793c21562ca1 history=e3b0c44298fc ansi=ecb61bffd21e ansi256=ed97a1f1aab9 html=2375703500ae
249+20/179 input=c7321f26aa4b vt=b2f88ab421ac graphics=6d505782c178 history=e3b0c44298fc ansi=e514cec2d55f ansi256=2f05ce045a65 html=e304819dcd51
250+20/199 input=1e64f0e712cc vt=459e975efafb graphics=0f85c60d8bcb history=e3b0c44298fc ansi=56387c036e8e ansi256=bfeda84d3504 html=a48d40ca4f47
251+20/219 input=c61722782b3a vt=9190bfc820a1 graphics=f067ec496b5f history=e3b0c44298fc ansi=45bf0573bb99 ansi256=6cbb9c7975c0 html=3b23062ea98d
252+20/239 input=c65e79b596b7 vt=d3c8edcf5fd1 graphics=a3a95cd20f28 history=e3b0c44298fc ansi=59e10a802b95 ansi256=dab2ffea8d09 html=c8c701b72531
253+21/019 input=6d8b599454bb vt=e50e4850cdce graphics=9258c91bf1d0 history=6ebc4b61f2b4 ansi=d14fad767c53 ansi256=9e4839c11686 html=518eba74c84e
254+21/039 input=2f3792505a5c vt=3f8418dcf338 graphics=edd491a142d6 history=f505b2de2e1a ansi=9f4b37c1b289 ansi256=b0c92a0cf22d html=fa2697e6e19a
255+21/059 input=50ba70575923 vt=596598247f57 graphics=174ea50ec6ff history=2cde5b0f65b4 ansi=11d6f5602c6b ansi256=3fa666485317 html=41b4c9987e4d
256+21/079 input=1a42a368e14e vt=3be5c7a9966f graphics=c426645bbdd2 history=dbe1817e0470 ansi=ef4d959165ee ansi256=07ba166dcf3a html=c9a40672ea7f
257+21/099 input=63df54056256 vt=b295b0f8bf2d graphics=36e802fe6bff history=22e67a9b0953 ansi=1a30d1904101 ansi256=d0d28a777232 html=ba2d6607611c
258+21/119 input=79df89b8fff0 vt=0db1c329e0d3 graphics=c8b780d37f64 history=ab7add1cd086 ansi=2cf9f805abf6 ansi256=3535c3153101 html=7d7915391dd6
259+21/139 input=ea612f912526 vt=c752acdac1a8 graphics=0227de479c40 history=b10111c570bf ansi=72518d3e245e ansi256=029947f1bff3 html=dea59c047bbf
260+21/159 input=aeec6f11002c vt=ac7d2948b0b1 graphics=467a390aa711 history=24ec315d181b ansi=fa7beae868b5 ansi256=fb0946d83c29 html=06e70ca42d9d
261+21/179 input=24c60e60e3b1 vt=947c888b5fce graphics=efb40f7c49d2 history=798d584342c8 ansi=df547f10afec ansi256=5bbbdd3ca038 html=1eeb28e01a3d
262+21/199 input=547dccaa57f2 vt=d641d1cb2344 graphics=ff664e7569f7 history=2fa0eac3eb0a ansi=c153660c3195 ansi256=de9744c0df8b html=cc94e437c027
263+21/219 input=580f2ee8bf6b vt=c24cc36b68cb graphics=b37f93b7361c history=e6d0f07fe46d ansi=1425654efbe1 ansi256=9f0b0970721b html=8432818c20c0
264+21/239 input=f1652e1ff7e7 vt=0d7501b75864 graphics=47ada5c8972d history=de469d69d99b ansi=bacf8fe6257b ansi256=d568d80203ef html=dfe930a2b881
265+22/019 input=01ba17ac85c4 vt=496cb010d953 graphics=f22af68f3b72 history=b7f0f7e99584 ansi=6eb40193751c ansi256=1c451df21b16 html=827985f38ddd
266+22/039 input=42f3c147fdba vt=a3c945d1206f graphics=ccb9f1f8aec3 history=c7e0e31fcf0e ansi=d90cd8db8990 ansi256=2f717b9573f0 html=2063a9c75ac8
267+22/059 input=b5272cf6b2c0 vt=d0e9e33e4c1d graphics=e6e24428355e history=aaeb10ce7c44 ansi=c85a689382eb ansi256=bb35fa6ad750 html=bc5cbb51abdf
268+22/079 input=df11fc0ea107 vt=0ef28c94e4c7 graphics=8a631615821d history=37f5de85229a ansi=ef6cd391b992 ansi256=b5de86d12a9f html=586083cbebef
269+22/099 input=c4176d57bf31 vt=1c723153a857 graphics=481ee10342ab history=a250b6417499 ansi=aa77d5716663 ansi256=d57198ace643 html=fdddf431d85d
270+22/119 input=1081c942b525 vt=b1b795f197d6 graphics=02b28bf3aa32 history=1bdee1ef0937 ansi=b6ea7c081f1c ansi256=ede92df0ea04 html=0de5a23e4010
271+22/139 input=cd85644bd3fa vt=be34e6a836e9 graphics=432fedf48712 history=6f54299845b5 ansi=51f3c1f48e96 ansi256=53a36e5a7b0c html=f37ec24a96f9
272+22/159 input=94e080045d0a vt=a63997ef6095 graphics=bae0c9f75b53 history=f4e3d587bc1d ansi=f6581e7652a1 ansi256=356dc4385c7b html=2734dcee119e
273+22/179 input=67502dd99a94 vt=0d12c6645323 graphics=e1fa932c581d history=48618f2eb924 ansi=e62c948f7b61 ansi256=2081f7d8fd89 html=ab1ed984b294
274+22/199 input=1a875e7489aa vt=30f0de781b81 graphics=79bbcc4a697b history=d74cb6820539 ansi=aafe502a3368 ansi256=803867175a8a html=fc1e839f63b6
275+22/219 input=97cd8f5e7b40 vt=329131c2c98c graphics=5d057491e906 history=761f4a4c1a0a ansi=8ce94a66a529 ansi256=30c70089306d html=321dae654bca
276+22/239 input=74ac88bf42f0 vt=6302e4338e3e graphics=8248f4385dc8 history=057a1e67dc5c ansi=26f0bf26e9d6 ansi256=b8b0feffbd10 html=7ba1561dda31
277+23/019 input=1ac834dd66ad vt=0703283520c4 graphics=9258c91bf1d0 history=d5e92dfbe7ad ansi=59ff2eeabc7d ansi256=4d98e3b459c4 html=1f588a40164e
278+23/039 input=52c7c552e18a vt=c7c6f6a3b87e graphics=762d16b098e3 history=4b446bb67c28 ansi=4f977bf9ba80 ansi256=62ce599a19a8 html=20cbeb3461b3
279+23/059 input=c728326cd041 vt=53fdafdd6168 graphics=15ef31cb4efb history=dfd246f6a230 ansi=259d4cb646a3 ansi256=afd261fca4fe html=b759e05e7e42
280+23/079 input=72846e647366 vt=64fac99bac94 graphics=212e4c08e2cd history=bea125990222 ansi=1080f1358b3f ansi256=cd3bfdd4c44b html=2e124eb47c51
281+23/099 input=6b584e536c32 vt=76fa20f1b2f7 graphics=279ae557dad6 history=1e92e99bf77b ansi=b3e9a6850cc5 ansi256=d1a86aac3718 html=9ad39e087f83
282+23/119 input=d1256672f808 vt=5fe9b2f6c14c graphics=52845616bc40 history=318e8e7794f5 ansi=4ea8c0bfe1e2 ansi256=0fb5fd863f3e html=e668e50f26a0
283+23/139 input=55d0a8e00404 vt=3f27f2fbead5 graphics=991903976c4a history=8423992a5268 ansi=e9e74ee182ab ansi256=ab9911e6e52a html=7cba44ebb246
284+23/159 input=3a92a89887d8 vt=405b4ec5829d graphics=a94c75564483 history=fcb99eb85aa8 ansi=a64c8cfbcf82 ansi256=10cbc31927b9 html=0085b8454be1
285+23/179 input=0d5a633cd93a vt=219797ad4bde graphics=cdbd6f5d52b2 history=002c612acebb ansi=c91018b65a7d ansi256=cdd0b78340e3 html=1228a2356628
286+23/199 input=c9c456495830 vt=fc7556378cef graphics=3bda366a4653 history=6a4964108626 ansi=6c0ae68c7db9 ansi256=a451eedd0781 html=4ad42d85bf40
287+23/219 input=8c41bfb460a3 vt=144903b07554 graphics=bb4b123e09d3 history=9b0ea55ebf1e ansi=2dc10f02a8d5 ansi256=17ab91693041 html=607a11cbb2ba
288+23/239 input=ccd5bae9d0d4 vt=3ee3e4bcf2c9 graphics=fdb9c488c44f history=433238a91160 ansi=b8a97608d2ef ansi256=52ef6c545a86 html=d1cbad075fc6
289+24/019 input=148102104127 vt=e22fcc59d5b8 graphics=f8979b697ae6 history=e3b0c44298fc ansi=40b1b6544cc6 ansi256=636b355a35cf html=2ef429ced7eb
290+24/039 input=018bead9b7ae vt=205c10c84d59 graphics=3342f04c7491 history=e3b0c44298fc ansi=ef8059fcac20 ansi256=1f000c7cc8c5 html=5c88341ab5a7
291+24/059 input=319607f49e0a vt=9cfdb3b9dd63 graphics=2b7e7b47aa81 history=e3b0c44298fc ansi=349f9af1db55 ansi256=8ea789af1a5c html=580f5c77e3e0
292+24/079 input=e6926c76740e vt=517f29d0eba1 graphics=edc4d4e288c8 history=e3b0c44298fc ansi=5210df2c3aeb ansi256=42d8552bc074 html=e9ac7656e9d3
293+24/099 input=c18757c3b799 vt=b3a83e738a66 graphics=c60ca86be87a history=e3b0c44298fc ansi=66b4681f9721 ansi256=a2b0bced4166 html=a9d1c68677ca
294+24/119 input=9861958c685f vt=b6e7b01496c9 graphics=c709a324064f history=e3b0c44298fc ansi=e3ce39e0ae12 ansi256=8674e90c5215 html=6d9550434d86
295+24/139 input=05cdfc1f5efe vt=038e0c505a83 graphics=193805159acf history=e3b0c44298fc ansi=3bb5071299e4 ansi256=822567388615 html=92f98a360d36
296+24/159 input=8e607996da30 vt=106b19e6ec5a graphics=8d6375572fa1 history=e3b0c44298fc ansi=d6f1c798ec9b ansi256=bba4bb627baf html=24ead4eae2fd
297+24/179 input=dfe92c6f2bad vt=a9348116c0bd graphics=cc914d760012 history=e3b0c44298fc ansi=1789b413341e ansi256=40f767a2dc82 html=58c9042c8c54
298+24/199 input=4c2553c2517c vt=02e131e2d775 graphics=7bb2aa5d8d6e history=e3b0c44298fc ansi=48beec3c3118 ansi256=d6123686c1d3 html=80edff930a81
299+24/219 input=11342eff7098 vt=8a82550741ad graphics=6d72ab39e211 history=e3b0c44298fc ansi=5c8067ce0751 ansi256=c61a4dc165c3 html=1d6c3461c933
300+24/239 input=7701b418b2c4 vt=29f384a3aac7 graphics=483f93084782 history=e3b0c44298fc ansi=76141e442411 ansi256=60b08d80a715 html=5e79b9d39bf1
301+25/019 input=52d18b6088cd vt=fca038dd5083 graphics=9258c91bf1d0 history=028563431d2c ansi=de864fbef6ad ansi256=da875ca937d7 html=988825f1a0f7
302+25/039 input=9371bf89fcd5 vt=8254bb5172ef graphics=ec94ae6cc7b9 history=c21a1e2aff02 ansi=e6312cb66040 ansi256=2de9bb4807d5 html=d38a6e4486f6
303+25/059 input=648f90254a8c vt=7bf7a9fe2551 graphics=f3e88db7524a history=2a7d136dc209 ansi=11532c02d511 ansi256=ce3e2ce9182e html=d93a806b0199
304+25/079 input=ac8a64fd0669 vt=9055770e92e0 graphics=03c96da25a3b history=695aba930edc ansi=909609df56dc ansi256=c698724afe00 html=161836d0b719
305+25/099 input=b9cf01acdb26 vt=8dd2058f433e graphics=21a529189863 history=5238bbd06b82 ansi=b5d4088e160c ansi256=0ff96150e2be html=1940b52d8463
306+25/119 input=410378a33ad3 vt=dace7518854d graphics=671c04cdbb2e history=ba8ffc54516d ansi=9daa743e922f ansi256=0f6bdecf771b html=abca3838f07d
307+25/139 input=d5c58840cccb vt=a863354d2e79 graphics=774c3af4a9d7 history=fc832c985019 ansi=fd8a33c8643f ansi256=248acfdd5b79 html=2d2a6142c2a0
308+25/159 input=c779a92ffff8 vt=59722e5604cc graphics=90138c047ccc history=784062fd993e ansi=4fd68de4eb47 ansi256=47fac1db6a5e html=c9fa450a5ccf
309+25/179 input=0f10e10ba19e vt=35008d097bad graphics=893057b33dd8 history=16953fbaeb54 ansi=3b27b5e8053d ansi256=7da8c6e6e855 html=78d28e5b20c8
310+25/199 input=0ca98a998041 vt=8efd480ed24b graphics=63413593bec4 history=47776a85fe59 ansi=7d7d4c66a6e8 ansi256=5bdb0d8d7bbf html=0ddc17f9e7e4
311+25/219 input=de28db3b700a vt=17daa62c7cfb graphics=dd49376c4da5 history=15a33d7773c3 ansi=ae80596f4399 ansi256=82c08aa54c2c html=7a6d084b97d8
312+25/239 input=7376fea910e5 vt=fbb1d592f8d4 graphics=91fce35d7281 history=9386c1fadc98 ansi=6d4a3a73dc23 ansi256=868fb03a774e html=8c0629d2bc33
313+26/019 input=fda9cdcb5b52 vt=facd51ef20c8 graphics=382c68b55f88 history=77c1e92b28ce ansi=2ca00c5ec060 ansi256=d468b0312f32 html=99c7671e334c
314+26/039 input=45dde463af51 vt=6351e7ebe54f graphics=2b4e93560776 history=6d6bea4b9262 ansi=27f8e6f34ff1 ansi256=5497e744c3f1 html=d35ad612683b
315+26/059 input=7da19667b980 vt=d0db0647cfe6 graphics=5489354feff2 history=2a69dea37d81 ansi=a198b376a5f7 ansi256=b9ea808c723b html=f0d8237c3bca
316+26/079 input=32a6d6a2b1bc vt=cf96bfc4e6a1 graphics=3f478b3003e5 history=9127b57731bd ansi=47fe1fddd752 ansi256=8c4757767979 html=140d6ef6fcae
317+26/099 input=6f6ab6c33f6e vt=8d0bd32b9860 graphics=41c51ddaef04 history=e1fc29444d46 ansi=ad7570e6e1a9 ansi256=54ae825a2d51 html=b5202ae161ea
318+26/119 input=7268ff0f428b vt=3570eaaa8987 graphics=1536a47eea05 history=d4ca4f97cc2d ansi=6f955f7061fa ansi256=9b376649c4a3 html=4af6ca84ff47
319+26/139 input=a035d95e4133 vt=31fd63dcc343 graphics=56623268bf21 history=9e9e09147d59 ansi=367469570f8c ansi256=c1d131bf9d73 html=8ba9423aab63
320+26/159 input=13dac00ab83f vt=f3886857efe2 graphics=9c93b507d033 history=1d61914d4451 ansi=a70745216d22 ansi256=38f3aa51849a html=d7d9e3d8e315
321+26/179 input=b74e39ac0058 vt=cdd2058ecb63 graphics=24b3d853ce9c history=40a77b124d6c ansi=2f8eeb70c459 ansi256=292c6f4b1128 html=ae88fcc454f7
322+26/199 input=644a9acc3e7c vt=4d3b7e94ad9d graphics=105f7d3ad244 history=bd347f14b6ed ansi=db8bc20b0152 ansi256=db77852447fc html=e9b1ffb17748
323+26/219 input=3a73386e101b vt=32bafcc85079 graphics=29eb959b5720 history=69a44f4a9e2a ansi=433ef0c96908 ansi256=ffc502920bda html=329de537b64b
324+26/239 input=41caba3e4176 vt=72cdbafbedfc graphics=f103e171dc0a history=e01e78beb0e4 ansi=42e5a332cf10 ansi256=ffc9fdbf7eaf html=506fbd125bbb
325+27/019 input=a0ab158021a4 vt=4c016f9ab6b8 graphics=869d15133c58 history=b02d2b5c146d ansi=a66af5fe25e3 ansi256=028c81af44b0 html=fc80a7830ed5
326+27/039 input=619d48ca4875 vt=24a873ab19d8 graphics=e591a2412917 history=93d77aa8b991 ansi=9627caaffa74 ansi256=7f76f10a45e8 html=93e3f0ec2811
327+27/059 input=37323836c954 vt=a7361b81ab9d graphics=27fc3572e7b4 history=30619de4a0ee ansi=786e44106197 ansi256=bf3797a8c835 html=9c5c832eb751
328+27/079 input=9a19b64b0196 vt=f1baaa7f0a85 graphics=ffb49c684293 history=37e041c6b820 ansi=f7f24c82de96 ansi256=a5f5110890de html=15c69493adc0
329+27/099 input=d12989c27d01 vt=a8fc3484ba05 graphics=c8e28e457332 history=a8279232604b ansi=98ffda5977b0 ansi256=534a060f046f html=e39368befb4f
330+27/119 input=0ac9080d8928 vt=b83980a4008a graphics=da849ea45a90 history=5c3d8be7a9e4 ansi=2b2e932c973a ansi256=21b8da618178 html=1c8956fa86b1
331+27/139 input=282ef624dfad vt=d6b004fd262d graphics=12a2e8a9f60d history=1329220e670f ansi=2298fb0d8a5b ansi256=11e812bae71f html=92e76791613c
332+27/159 input=a01c716c963c vt=13e121a5ed05 graphics=e6459b86b3cb history=3eb84b471759 ansi=f690218fe3b4 ansi256=fc21b25f6924 html=2621c438c156
333+27/179 input=20f00a694447 vt=94321f06be09 graphics=a3c4c9c6f33f history=42d4520330a0 ansi=a2a46388663f ansi256=a376fcbb8164 html=655351f8ba42
334+27/199 input=fdb67ef93b9d vt=1838510afa9c graphics=d29b34fbd961 history=df63294e32fc ansi=827143c01f7e ansi256=b85859dcbdb9 html=035cf7541b52
335+27/219 input=8ddfbab95f21 vt=e45174a8db12 graphics=c97d30325b64 history=62fa448733e2 ansi=32121881889d ansi256=4b64757e726c html=bc0256e425bd
336+27/239 input=753e7bf06dbc vt=60f1105433d5 graphics=efbf1f464724 history=4a90c407f9c4 ansi=c4071852a228 ansi256=1f57fb29fec1 html=f02e632104b0
337+28/019 input=391f94dcf6a1 vt=39ec4af818c0 graphics=9258c91bf1d0 history=e3b0c44298fc ansi=ed7d4a6a2cf5 ansi256=f02d1647a112 html=0c6fd0634bab
338+28/039 input=a2dc4b392a48 vt=b8e0c66df113 graphics=83d520edbb4f history=e3b0c44298fc ansi=5c501391013a ansi256=048ac49fbd32 html=c6cb7696f2fe
339+28/059 input=9512e505bd51 vt=3fd50ae5cb19 graphics=2a04a7e76271 history=e3b0c44298fc ansi=38d1d62d4cdc ansi256=7341cbe0d85b html=fa39f477d565
340+28/079 input=b4f33aa964fd vt=e8a914500faa graphics=b84eb0ef5e85 history=e3b0c44298fc ansi=5d58e0f3cc04 ansi256=0bef41c71264 html=c9b7d0a74d28
341+28/099 input=42c86901a419 vt=53cfab76eaf2 graphics=e919013fbcfe history=e3b0c44298fc ansi=d60a7106690d ansi256=674909bf361d html=9168b1416cb6
342+28/119 input=e00da70055da vt=7de1f675883b graphics=f2ef9f6ac5a5 history=e3b0c44298fc ansi=2aabcf8d8eee ansi256=168b25bf2b19 html=e22b7e487e36
343+28/139 input=d750a1ac07d4 vt=b315c0f1df33 graphics=ab0ed3a804ae history=e3b0c44298fc ansi=e9d617aa4089 ansi256=fae71b6133c8 html=01972989965e
344+28/159 input=3fc7f46eabe8 vt=ccffd168fd63 graphics=ec03ac4ca0cd history=e3b0c44298fc ansi=11a6c758321d ansi256=e80ed90c3bcb html=f4bcab9117e6
345+28/179 input=1d4acd9c4af7 vt=8bf36c9b23ee graphics=1911cb9145c5 history=e3b0c44298fc ansi=56763f90b125 ansi256=d9a87c01b2b1 html=d002b29e05f2
346+28/199 input=1856f88796c2 vt=0abd510a59d6 graphics=057f85e08328 history=e3b0c44298fc ansi=b0d6f894f6da ansi256=aeec9cff2fcf html=57f2df151504
347+28/219 input=cd27a5fd4004 vt=4ac4f7028196 graphics=a5316d8dcd5e history=e3b0c44298fc ansi=aab02f46cf70 ansi256=5b2060872b3f html=c2469613e79e
348+28/239 input=1670f4358e8c vt=89328e3b3947 graphics=d91c8b353650 history=e3b0c44298fc ansi=c75943df0217 ansi256=919688b315c1 html=d1989ca8a68c
349+29/019 input=d2b5871bb414 vt=c052ae09b304 graphics=9258c91bf1d0 history=d3fd1a0b8244 ansi=91c870d1933c ansi256=f4e29987bead html=b4d07df3d6cd
350+29/039 input=5b0a2705ef4d vt=0d059bd5f42f graphics=8142d34d582c history=92f9707352a1 ansi=b43e08309a86 ansi256=19b9af5d6ae0 html=fdc190cf1253
351+29/059 input=47ada4f1019c vt=b40f6e177d1d graphics=1e0eb8920f76 history=6db573d69703 ansi=41ccfb4ac2df ansi256=649bc6b5da2f html=1e5bf7f9470c
352+29/079 input=8bc9e83b5a81 vt=374c8594de2c graphics=0532805773dc history=46255be21ecb ansi=765157fbeff5 ansi256=b88f874e8c6b html=072a60554e2e
353+29/099 input=9f1e5c464abd vt=aa59b0b22cf3 graphics=d2d3cdc33260 history=37760bb8481b ansi=989b753bd4f7 ansi256=7050ab6e10f1 html=8b9a85f51a19
354+29/119 input=cfc6143e2e7b vt=1acd379f3bed graphics=c7f90dde3e58 history=067212979178 ansi=b0093eb9ed2a ansi256=0219a9bbbc74 html=91eb9810990e
355+29/139 input=6953c4cb1ff3 vt=da2df4505df2 graphics=d87e27f1fedd history=bbbd1009cb0a ansi=45612d00f8ae ansi256=aa563cf04415 html=1a16506e94ef
356+29/159 input=7625b8495e7f vt=865ffd108fda graphics=b39ba83c432b history=3556ac8bf0d7 ansi=df732e1bf1d2 ansi256=ec385b448b4f html=a2fecf7db3fe
357+29/179 input=b321a53fe360 vt=69d2a8985995 graphics=58400326653e history=8f690969e6f2 ansi=a64950b43d96 ansi256=d7489c15a4fc html=2ad62006a5e0
358+29/199 input=37191c6fa49b vt=51dd26cf6374 graphics=c98569c74a00 history=a2bf34248497 ansi=f956527071d1 ansi256=4a45079fe8e9 html=be2bb9129a02
359+29/219 input=55e0459a5d06 vt=570ab6ceac22 graphics=5ffd6c200c89 history=52e3c5d61685 ansi=17dc0c38ee41 ansi256=5ddb6f47a5fd html=fc6cb77549f6
360+29/239 input=3423aac00df5 vt=1c71bdbec8c6 graphics=66cfc819e87f history=0d94a263950c ansi=37c75f4e6ee9 ansi256=9cbe40931eff html=249158fb98cd
361+30/019 input=81b751d4ee69 vt=cd8eb7cdf707 graphics=c8d8b5e0d84c history=2c3d149755a5 ansi=46df2034c3bb ansi256=5c4635e74a7b html=ba6e227155d4
362+30/039 input=f2ea78ebc633 vt=32f6e4b794b5 graphics=0c4a8732135c history=d2fd3d71ad52 ansi=5d06683bca49 ansi256=2e3c3f8e2573 html=08fef3cd9bf8
363+30/059 input=b5b88be76b35 vt=a89c35759631 graphics=0a16a95018e3 history=dd5821495eb2 ansi=8212058f2c16 ansi256=bf999a03348f html=a120f8550939
364+30/079 input=aab80cdb1a9d vt=bad39e3cd313 graphics=fbde544e97db history=a6b95b04c20e ansi=bb5e412c315f ansi256=d3806cd75402 html=f3b857fe9281
365+30/099 input=fecff317770d vt=dcfed4e41776 graphics=62e6fadbeb33 history=f0143cbc9235 ansi=372309dc5b18 ansi256=a1a2575fa6fc html=10213ad6969e
366+30/119 input=f36a0921e2c1 vt=c1c87f7aa7d5 graphics=0e5650a6b594 history=2539236c8d07 ansi=b44c19672ced ansi256=e63496a082c5 html=40fe33da0bc3
367+30/139 input=1235b90e027c vt=92378b77cee0 graphics=6570bcfcc284 history=29f785a303ff ansi=f95d045ca021 ansi256=96ba741a02df html=a02c2c05f24d
368+30/159 input=0a9c4944432e vt=c1c4f164e2ed graphics=9655c95832a3 history=5cab22d70e85 ansi=4d8b73aa1781 ansi256=d017ea26c731 html=9d428fd38757
369+30/179 input=8188ef7c5aea vt=9df594a81c83 graphics=6135d5ea25a8 history=2171fb6763dc ansi=746fdb74c702 ansi256=4403fc8df293 html=f17ee03f7c5b
370+30/199 input=4abad5b6d552 vt=e0ffd787a8fa graphics=c3ff71dd99e8 history=8c073ea7f31b ansi=877f98e30188 ansi256=8a662a41ab7b html=9f046facb643
371+30/219 input=c466091ffc3e vt=6fef0ac7c1b5 graphics=92faa40c0c50 history=de0ca81512fe ansi=cf605527be7f ansi256=d982cf06fa77 html=728ea5986192
372+30/239 input=4145ebca2134 vt=43dee83cd99c graphics=a10996d846e9 history=9127a917775a ansi=48031030271c ansi256=644c27c658cc html=520641374e9c
373+31/019 input=4ffdd107e130 vt=a8f488f70e96 graphics=54a47f32d294 history=1363d4610810 ansi=d12a1938e477 ansi256=b3d7ac12ba37 html=709869c68aa7
374+31/039 input=580dc6809479 vt=26d09ae8088c graphics=932b610185a6 history=546bb0ec07c3 ansi=3d73d7b4ece4 ansi256=c9f2585ef571 html=c1b184bd2031
375+31/059 input=d55047314620 vt=ba8944f37704 graphics=93f9c09cc57f history=13263e91f3a0 ansi=b7e22aa137a1 ansi256=ac0dee7439a1 html=6c0652e529c3
376+31/079 input=481041bbdeb3 vt=7e2b3392c536 graphics=96a7f4c0e9cc history=b4e2710a711f ansi=5bd2e666b439 ansi256=f75b592537b4 html=a4af462fedcc
377+31/099 input=a0faf263fb01 vt=b8a49978e022 graphics=8102f1a4335e history=2fe4211ff34a ansi=be22be7e7f00 ansi256=879a70e29f04 html=fdf426a8f598
378+31/119 input=187877e7efa8 vt=73e5614e80b2 graphics=9569fd17b61e history=241eea6af7a7 ansi=8bc768ccea64 ansi256=a5c49983195b html=cc65f0a09f0b
379+31/139 input=de7b035ba613 vt=9dd8609cafec graphics=d564f22f470b history=0184633328b3 ansi=4bdf20abbc23 ansi256=330f23d0aefb html=42ed22d9a936
380+31/159 input=b6fd5e5706dc vt=797000293a6b graphics=7a52d325bebe history=7610ffcf2c68 ansi=b3fd23a46a82 ansi256=eccb38052f3f html=0038d1a5f1a9
381+31/179 input=8c6baa09d601 vt=14bcb2ac1ccb graphics=c47105a03d8f history=bd6755a03aeb ansi=f5bad7cc857f ansi256=f4e17410acaa html=895199ed0c72
382+31/199 input=e93f7c591ad3 vt=6d96a17aba6f graphics=2f720cb29179 history=3a9736691489 ansi=460307957329 ansi256=80e672ca3ac0 html=b6718ba45e5e
383+31/219 input=79773cf0de2d vt=186bf619a34a graphics=f49eef257c76 history=5aa2cfa1b249 ansi=ae7c27b07155 ansi256=7c18b74d2046 html=0fb7696ea8eb
384+31/239 input=6c9d844e01b7 vt=54d6672972da graphics=121fb62a4ac9 history=973c3872c5f5 ansi=0d6dc977f68d ansi256=8dfe6cc64918 html=8bd17b2d00fa
385+32/019 input=f1b9f49825d1 vt=b896febefb87 graphics=5b44277a67f0 history=e3b0c44298fc ansi=a59d647eab6b ansi256=dac7099fe2ea html=834f953e7816
386+32/039 input=2a33a289496a vt=b5916d7070fa graphics=26d5bc17baae history=e3b0c44298fc ansi=7f524a65348d ansi256=0db81005952b html=2dbbc99315ad
387+32/059 input=c744aeba9d35 vt=1f7ab0ed0a85 graphics=19bea48d4bbe history=e3b0c44298fc ansi=48f20dcecafe ansi256=cba05808b822 html=cd106657a417
388+32/079 input=a291715ca604 vt=02dae80575f6 graphics=cc3ccd321b8f history=e3b0c44298fc ansi=e60a2f443845 ansi256=fe695b1b74da html=5e5dce1dbcfb
389+32/099 input=0185338fbcae vt=8fc5a3e651b4 graphics=2f6b60f4c1bd history=e3b0c44298fc ansi=6bbbc41196a6 ansi256=d1c3be6963f5 html=38fbc5c0e198
390+32/119 input=5bdba58e56ef vt=fae5a689ad92 graphics=ad43c49b7a64 history=e3b0c44298fc ansi=0ce313ad92c0 ansi256=c13d348e44ee html=691cf37c35d0
391+32/139 input=c1db2991e5c9 vt=54093b9b2429 graphics=3df6b10ab88c history=e3b0c44298fc ansi=e31e25be2279 ansi256=f64244a7e151 html=691a9628b531
392+32/159 input=591789c42d4b vt=c24909ea2afe graphics=c236f799ecaa history=e3b0c44298fc ansi=022f0da69021 ansi256=239a7a465997 html=8e5993493cfc
393+32/179 input=65675fdd79cc vt=19f4b67d3b4e graphics=261327b79d5c history=e3b0c44298fc ansi=a3b2504f775a ansi256=afb363d453b9 html=201666f5a199
394+32/199 input=05390be08cb1 vt=4bc9f1107e39 graphics=fa6550382379 history=e3b0c44298fc ansi=89d28c0df975 ansi256=805ad4ff7ce5 html=ebc32b3a93e8
395+32/219 input=80d7f0067852 vt=d430bffec709 graphics=5c1d55bc5c72 history=e3b0c44298fc ansi=06fda943d841 ansi256=a76bc4ca9ca4 html=088e8f8b6c28
396+32/239 input=9971f0ae2fa1 vt=9ab36840c246 graphics=aa7fa2241277 history=e3b0c44298fc ansi=1c7e054f03bd ansi256=f377130452c0 html=96b525a29e6c
397+33/019 input=4d8ec4a4118a vt=223f264f2447 graphics=88d9ff5277da history=711a38708632 ansi=080247111071 ansi256=db0ad0bd8b9a html=8578a4d939fd
398+33/039 input=72bd61b19dd6 vt=525fb700abae graphics=cdb95740eded history=0d7c8ec46243 ansi=292ed59cca0f ansi256=5370dc6a7441 html=2cb3a89f23a4
399+33/059 input=230c9af2f983 vt=e49b983f0af7 graphics=a9ef4a02744c history=b77790113127 ansi=cb2676a2038e ansi256=adc4188bb526 html=8b3de2c7c4b8
400+33/079 input=4df91df6e37c vt=fb750cb35392 graphics=818dbc92bea3 history=23a3886975c8 ansi=13f3aa9761bb ansi256=064a59ef4fc6 html=73c2a40af02c
401+33/099 input=678d23120ba3 vt=6d6b38fb0388 graphics=92ab0d9966af history=2ca97bd48c2f ansi=d0fbb5b13d15 ansi256=c0d1412e905a html=1491accb4ed3
402+33/119 input=bcc5b1e12cec vt=3f46ce9c8abf graphics=ec245d1603aa history=5032daa96a10 ansi=83456a35b8e7 ansi256=7860a7f16450 html=ff85921dc9bd
403+33/139 input=3adcc6ae924e vt=b9fde658c5a9 graphics=5ad851d25e4d history=3a916388dafb ansi=f3cf449bbd60 ansi256=b72ae24101a9 html=61ae977e257d
404+33/159 input=fb7643e0bce4 vt=74c506f158c0 graphics=5b509853d2db history=877c1724a1fb ansi=fa29a37cf87f ansi256=fcac20dc9549 html=2548f41db282
405+33/179 input=caa52db0cbdf vt=e75162de1b89 graphics=d949a79b005e history=bef9891a91f3 ansi=1b75efb5c608 ansi256=fc91fc6f771a html=82ffdfbb26d7
406+33/199 input=c2671cae6a9f vt=e7b36b067938 graphics=d6eb2ebcb29b history=7334f6641140 ansi=0b8aa22b4190 ansi256=49b67dd6fae1 html=a4d1eca5d7e7
407+33/219 input=e7cea0a5df37 vt=1de3013b4d64 graphics=cf342952544e history=f0e0478fb828 ansi=23b4346842b6 ansi256=1866c47845b6 html=63bc52ed79bb
408+33/239 input=5e15a796e7a7 vt=9665e614c843 graphics=94587b3237d4 history=6be392d9a77c ansi=f69f3eaf9883 ansi256=4275a0f5d1ea html=fc5fc2a96c78
409+34/019 input=178da8bbf142 vt=205910068395 graphics=dbfcd55d0b33 history=7502eeba6bb8 ansi=8163280cad67 ansi256=159b42c6fac6 html=953e473e01fc
410+34/039 input=a1bc6765e27f vt=48042beef7b7 graphics=29f7f17a132f history=6ec8d7f5ecca ansi=245569305424 ansi256=13017bde2cac html=f75731ef87a0
411+34/059 input=949398406918 vt=90cc3b7424e8 graphics=8c7bfaa71c9d history=8638567d108a ansi=e21a53a5acc1 ansi256=d4d06f3e4053 html=8f242eb9352e
412+34/079 input=9d2e927f6a2a vt=3d041543a44b graphics=8cffef3c56ba history=79b1b371a8e3 ansi=082ee3283735 ansi256=8ed8beda9444 html=f229a8e62de4
413+34/099 input=28020b63bbd6 vt=32c06be61be0 graphics=20301a3655ce history=6679d91bbfd4 ansi=42bd595e6e1e ansi256=afade28b969a html=d77c51a7fc40
414+34/119 input=daf68c036c3c vt=af9c947f7422 graphics=5441da3a6af7 history=adbdbeea589e ansi=93a79bdb653b ansi256=82786c1b4fa3 html=0983d1771e07
415+34/139 input=6d25662acf3a vt=5cdb4756e6b8 graphics=ae0700fd7a09 history=acd95dfdc46d ansi=0b761099f515 ansi256=0ee389babd62 html=b09e98948277
416+34/159 input=b65ddcd437b9 vt=540ab8b4a6d9 graphics=71afa643a19e history=95e19294a4cb ansi=e1cdb7e662c3 ansi256=733d11b8083f html=83f8842bbd2e
417+34/179 input=57f1f81acb3c vt=41ece03f7923 graphics=7dc07edadc7a history=ce5abe9435b7 ansi=7d026cc1a611 ansi256=15f91df0de54 html=01710e6ff318
418+34/199 input=3a7b3c2440bf vt=a9150ba7a4cb graphics=52db9cf3851a history=e14f94ccdd58 ansi=2a2474a89a60 ansi256=0537f46cd650 html=295390e7c9e6
419+34/219 input=76c4c4ccc65d vt=ac0da0319944 graphics=59162dcc7a6c history=3f8c45dc183b ansi=49a40bf933cf ansi256=15bd13cb4377 html=d356d7e4aec0
420+34/239 input=74a38b340785 vt=754f065a06b1 graphics=784b8e4a91be history=8af536dda7f7 ansi=a858ae00e59d ansi256=dd5c4ca64682 html=a77267367f14
421+35/019 input=e01695bf4e50 vt=8d5a98309b21 graphics=023952274cf9 history=2659734a87a8 ansi=b024edea8c61 ansi256=d5f38420be8b html=3515ae8035f2
422+35/039 input=93665be63313 vt=a35f7be82f67 graphics=18b07a725813 history=7e0e18d77c74 ansi=390a8472c45c ansi256=6f6a93364ee3 html=8ae2d5763ebb
423+35/059 input=dd1cc03b3572 vt=6afa913190d6 graphics=14547246cfc9 history=be2e3ffa555b ansi=31f3ce2ba63c ansi256=3884c9872e16 html=3444412498cd
424+35/079 input=44796a406918 vt=6ce22280a030 graphics=8244d770854a history=30ab815d28f1 ansi=02a0bdfbbcd6 ansi256=8eb3b5dd6ca5 html=035d2d2e090f
425+35/099 input=43ec30d13ab6 vt=13cafa9a15c4 graphics=c8de2510382b history=de35b2cda662 ansi=18856574b289 ansi256=803599ee7085 html=20449628df2c
426+35/119 input=51d29207da68 vt=cc52140c5b87 graphics=569a06ba1c26 history=ae9194ed626a ansi=3d3a69a1cec5 ansi256=a619ec705a9b html=2f61a9b55f28
427+35/139 input=b6e1eac19c21 vt=87bc9c96ee66 graphics=a761438c266b history=c565c9eb5e67 ansi=8b92e0851a34 ansi256=4ffa0b70b26c html=89caf046d441
428+35/159 input=b720c6dc8986 vt=5460691c9f91 graphics=1b8ce71ffdce history=6dfd322c6901 ansi=1728d0c18bca ansi256=b7b1df41146f html=72290758bc08
429+35/179 input=0341f9cb3b4d vt=7336edcff9a8 graphics=ff521966f503 history=c556c9bddb2d ansi=df31635476c2 ansi256=2259657c5fb8 html=85bd9cee86c2
430+35/199 input=1f9be1f8195d vt=e1efb6275a87 graphics=806918fdf91b history=c577342a7558 ansi=0d61fc403ed4 ansi256=3dfe6c2d3f95 html=79cf3e389d27
431+35/219 input=1706e3dc7ba6 vt=4797a5f1c73a graphics=9c0eb19d32f4 history=9448c87c1fde ansi=4093919d80c9 ansi256=e8391c2d9989 html=0398443da2dd
432+35/239 input=880a5d50813f vt=06531473f963 graphics=0dc2013efaf5 history=449d96644a4f ansi=250e7eeabc3c ansi256=4c6fafe74d13 html=464da1cb9915
@@ -1,432 +1,432 @@
1-00/019 55a72c4c8d1c1a0e00550a151+00/019 input=34fc58104b22 vt=bb9b826cf048 graphics=c1313fa59940 history=e3b0c44298fc ansi=558b1d465cb9 ansi256=7c62df9f88a6 html=57085dbc6bc7
2-00/039 4beaddfc77e4110f80524b382+00/039 input=957f13b6dc6d vt=d580503f0b0c graphics=d9a508723211 history=e3b0c44298fc ansi=d8801a468cd2 ansi256=4e4fbb5a75ae html=6f9f51bb389f
3-00/059 a5c2085be8baec4f551edd923+00/059 input=02ca4e7f645d vt=8f0ec905b4dd graphics=ca7e3df19c59 history=e3b0c44298fc ansi=22e9db71432b ansi256=c94537d35e21 html=77e2381b2833
4-00/079 8bb94cfe1ed22a49a4a87e024+00/079 input=e7459a0424b7 vt=658a98490259 graphics=2294ead167f8 history=e3b0c44298fc ansi=a769731d8a6b ansi256=dfaab9ed690b html=9331f082e0c7
5-00/099 d575a05b8d36aabeed57f4bc5+00/099 input=65861d80c11d vt=3dff2abbe571 graphics=49a531a5cac2 history=e3b0c44298fc ansi=b9610fa412a9 ansi256=d9a001c8d0d3 html=bdcab0b42f1b
6-00/119 40726b31f079ddb1206aad616+00/119 input=b7bbd6cab918 vt=802dc307f264 graphics=4dca1d671bb5 history=e3b0c44298fc ansi=94ed76fcf0d5 ansi256=cdeba8de8f99 html=b646697de0df
7-00/139 22efecf809e0cb839cb073d57+00/139 input=e1957aa581c4 vt=e59eed292827 graphics=c7edbf6bb08c history=e3b0c44298fc ansi=bf1cd5adba0c ansi256=4b00e8ef793c html=73f7506b9438
8-00/159 543183f4a516938dc9348a4f8+00/159 input=72d2e266bbee vt=ce72286ff858 graphics=9d08071cbfe7 history=e3b0c44298fc ansi=3473f0b036d2 ansi256=7caddc9fa2d8 html=6a98d3bd5931
9-00/179 4e20ff78f152fcbe5137d54b9+00/179 input=5f03942bb446 vt=909794a3080a graphics=c4be9e09c930 history=e3b0c44298fc ansi=43919248cf80 ansi256=15e239bd6430 html=23461097c399
10-00/199 7037d94f724ee16e55d96bed10+00/199 input=537e6ea131ba vt=ed5b1e654b14 graphics=be52bd862e04 history=e3b0c44298fc ansi=77868d0f1ea5 ansi256=91351ed686ae html=4e7ba65fd552
11-00/219 6fbae174dc09053ec6f6bd0711+00/219 input=0d15f7a3b67c vt=4fa431325c0d graphics=79964969d8b4 history=e3b0c44298fc ansi=1dfbb31f7937 ansi256=0929b8057746 html=582bc75c8e8d
12-00/239 b9cc6a0d303e3b79c13f8d1912+00/239 input=7c8d6d2373ed vt=bb9c175f8153 graphics=9e5082990084 history=e3b0c44298fc ansi=2ccb101439ce ansi256=7d50c7faac48 html=a98bb992d270
13-01/019 92d98f04143705d463e00d5a13+01/019 input=cbc8877bed63 vt=22ab1acff1bf graphics=c5b8fe57cfa6 history=fa5d8f18f68d ansi=afdab3ddfac9 ansi256=48c65d2c43e6 html=02caebc851dd
14-01/039 0c887b0db21e564acbeb140b14+01/039 input=d0cb0bd869c9 vt=f58c883883ec graphics=22628079d8b2 history=386f8088a60f ansi=d592741d1509 ansi256=fac3d9aee1ab html=bde87d40c7e5
15-01/059 4a1d21d32fb2e2dbb8a0a04815+01/059 input=e25ff0ff1a54 vt=f329087d99d8 graphics=033cd4eb10d0 history=241434fd3fed ansi=d6547cc1881f ansi256=6e78b18137e7 html=578f8efbaa40
16-01/079 8c494398433b3f3292105b6816+01/079 input=4de36294e2e7 vt=0b491efe74c5 graphics=e3e861b21b99 history=3e3751cacfa6 ansi=36b333e14ee3 ansi256=f581315254ff html=7a358839f40a
17-01/099 878ad5680b0b65efb2788c7817+01/099 input=2b7fa8b73e54 vt=cdcf0feb0ab2 graphics=7b1785222ace history=6de5f14c9b3b ansi=318c8c763741 ansi256=edeaafe2bf97 html=a6cc5cc4dc10
18-01/119 eba0201db6d4a0a544c7bc2618+01/119 input=ed4026577ede vt=47cfe6da14c5 graphics=1f4e90d00dbe history=9fc31e684946 ansi=511a067be740 ansi256=075aaf679ea9 html=5ba0d816280d
19-01/139 ce963cc5a23ffa5df867e30f19+01/139 input=16d884839d5e vt=b47acf684680 graphics=aba320d6ac2d history=c694cebc9c6d ansi=a21c3e6b2c56 ansi256=d66750dd1f13 html=7bfd11f66888
20-01/159 955c009f90fc40447bef222f20+01/159 input=ae726a283ab9 vt=124d96154247 graphics=7c92abaf9499 history=1b394f493a6e ansi=e9bb095ab5e8 ansi256=c6e07402bca0 html=60840af2b8ab
21-01/179 63624eaa51d667926773f7d621+01/179 input=4002bcdef56c vt=ae28edda6428 graphics=874c3d3632c4 history=f97e91c814bf ansi=1476dc66f1dc ansi256=e3d9c1c5f152 html=377eadb17b87
22-01/199 742853e0e88b47c1d665f98b22+01/199 input=bcdb0bb395af vt=6c6a86726ea6 graphics=408aa5c32aed history=cc247d46dc5d ansi=3900e39db02f ansi256=a1003c8fd5ad html=0ec54e438114
23-01/219 c171d410ea73dbdc7160752023+01/219 input=b57a1b43c9ed vt=33212d08cac6 graphics=915c35a9e421 history=55df44fba064 ansi=a697afce6763 ansi256=4afd404912f3 html=6f57720f0bcc
24-01/239 d009dd0730df60baf58c58a224+01/239 input=5a6d7e54e43f vt=064445a04eb4 graphics=08fa69ab8d7e history=ae06c8614ee7 ansi=ec529ccb7d82 ansi256=da4537b03b71 html=e176c4d39894
25-02/019 3e82372b6cb2ef730fbd402c25+02/019 input=e128155ff5ee vt=6165a679180d graphics=9258c91bf1d0 history=417faca887a1 ansi=c76da783dd51 ansi256=ade5d4699a5a html=5c12498e7f09
26-02/039 398deed5e521d0788101775d26+02/039 input=f55b6f5f0ae5 vt=6c13343e5e72 graphics=ec94ae6cc7b9 history=a98f1d645add ansi=9d23bdd6b42f ansi256=34b777e364eb html=7421f1e2339e
27-02/059 21401dc4b8bee3c8c6dce2ff27+02/059 input=efecbfa91a37 vt=f15094e108a2 graphics=2cc2c4f89334 history=c354c025cf5c ansi=31a27bd463dc ansi256=f7cb938291b9 html=d1172b288064
28-02/079 22edd985876e2267fd4a689628+02/079 input=5569bc9cc096 vt=d49d527484f7 graphics=20fb47c1a763 history=5ee55bc12a28 ansi=2dc804e97027 ansi256=6f3132f4c824 html=cf0a7fd2cd04
29-02/099 e6c6c10fcee0f3be94cdc63e29+02/099 input=818abcb54d25 vt=79b2c236e761 graphics=2988687caeb9 history=772aefdee759 ansi=eaa23edb44d4 ansi256=f0c638352747 html=e975b06011c0
30-02/119 4cc31105a1fd3951dbc19e7830+02/119 input=0953c14a91ab vt=3255a5b7edd4 graphics=66394393cb3e history=40e37b86d83b ansi=ac12ac48a6d9 ansi256=786be89622e7 html=c2a8cbe382cd
31-02/139 ff2da75e170b01030791f70331+02/139 input=097eb426b6af vt=cd9241f4e821 graphics=985e13b357ae history=d0c1aa3cc624 ansi=81d1a99de839 ansi256=465cdb5a2331 html=a4153acb0e41
32-02/159 ee1b1a0baa2e690f004bac7c32+02/159 input=38bd63bbb187 vt=c6a6eaea70b2 graphics=aa9d4f7d2ef7 history=0de5f5ec693d ansi=6ac3fb8d4c15 ansi256=6d6993b9a7fc html=e2cbed3a72e5
33-02/179 70044ab48fec67d54592058a33+02/179 input=8ae111814233 vt=8fbc292c149b graphics=411e2f4f1d49 history=fdf4efdc191b ansi=abf0b4964a01 ansi256=2a7e59c820a8 html=5369dcb88366
34-02/199 73e6310d3e4c2a02a0aac70f34+02/199 input=4213f245636c vt=c1d2f7fb395a graphics=5bfa4713d56a history=f5e53a839d08 ansi=7e4c5ba3abb2 ansi256=d2aa15e8b380 html=48adffbac091
35-02/219 38ffab48e284151fed6243a135+02/219 input=931fd5b7147d vt=c659827ccda1 graphics=1651f31f454f history=98009e23090b ansi=fe65923b0e7d ansi256=c7537bce4e9d html=f7dd3b851411
36-02/239 dee6444cff6f5bdda9f190a136+02/239 input=8176a5e301c3 vt=c9d8342717ba graphics=fa8374156c82 history=09807ad0d1da ansi=8f8756e5bd05 ansi256=b6612363d590 html=98d729501758
37-03/019 23e37ad503fc5be744f0096737+03/019 input=77c9efeb3d0d vt=9dd67d6ea65f graphics=32c8e22c58c9 history=9b00e5d5c883 ansi=bd1117ecc4ef ansi256=215c0a0c57b1 html=c8d2199048c7
38-03/039 ec34adbb74097df59cc75e3238+03/039 input=935cc14c51ee vt=b936be15b17e graphics=fa83d34babef history=53a5b6b99603 ansi=4dbccd5407c6 ansi256=1a21508da4df html=743c05c22684
39-03/059 85c664d4a3ad1d484c5118b339+03/059 input=ecb91d159cb1 vt=e4fceadf53cc graphics=6ee88ceadd09 history=6f799dd4518c ansi=c7f5ad8c750c ansi256=ba17a1f0e9e4 html=390e3c978264
40-03/079 902369e3cf92b7cada2e9f2040+03/079 input=cc2cd5bf9438 vt=5dd5e31dc91c graphics=a6faff22c0fb history=4c160d4c8f45 ansi=6eb8fa2cbfe8 ansi256=f575b7123b3e html=19a9a215197c
41-03/099 008d777b9692c94433ca31e041+03/099 input=34c42410c4ec vt=89b335bd0924 graphics=ca98374af1a4 history=a1f40bab9f65 ansi=9286621ea5a3 ansi256=13c85dde6f2b html=2f2809220157
42-03/119 83d72044067f5276a4f75a4b42+03/119 input=699e8fffe957 vt=dcffdbdd8be9 graphics=cb0060e5f99a history=9abbb7c01a69 ansi=ee808efefd2c ansi256=9817a2a6e477 html=7f2515b0d4c5
43-03/139 0cdea02f941f932699118d8e43+03/139 input=54491f16453e vt=0cda44af54d3 graphics=c1b2ccb71270 history=45387defc739 ansi=abe60f4d1602 ansi256=d6bc368e5286 html=524dc7f0d0a0
44-03/159 dfd6d2abbad3a1be1e3d6ecc44+03/159 input=36e653d4e326 vt=88d69714c293 graphics=171fbbb1cccd history=233f4b0c2757 ansi=e2a055de3f87 ansi256=3a40282667b5 html=e8c71b93f771
45-03/179 99e59e60677d6d5ec88631a045+03/179 input=abdc7322ccd7 vt=83b89bd0be8a graphics=c26da5657c11 history=f56741685971 ansi=d5ccdbca449a ansi256=dd0425640064 html=10c0b6c45bf6
46-03/199 8fe8fc36ce8901c3bf214f2346+03/199 input=70dc8e14e40d vt=368c5ce18628 graphics=d5de3993daba history=31647d60d27e ansi=39a12dd48435 ansi256=6b0c5ab24849 html=52ca4c678d86
47-03/219 a27e68abb075486983744a0247+03/219 input=19fb2dbf2b72 vt=5560f3c4e401 graphics=65eb029b7820 history=035984b53269 ansi=76e9d9396925 ansi256=fb130cac7f93 html=bbaf4c191a14
48-03/239 5eb1a5f31fda06ffcf7e74b848+03/239 input=7c0c5314aeb3 vt=a0dfae216688 graphics=5c6b4ae18b60 history=16d405a75917 ansi=70a2961a921f ansi256=0d5cef42c7e7 html=7a9861f18818
49-04/019 4faa96c672855d38d5f009b949+04/019 input=ac95ee6bd1c4 vt=75730da64833 graphics=950dc65636f9 history=e3b0c44298fc ansi=1d40192d7f5e ansi256=7dd8c5f69449 html=a90d40d590c6
50-04/039 45daf6da341e0be75217614350+04/039 input=b16461f2d459 vt=89fde5beaa91 graphics=dff172a47e3b history=e3b0c44298fc ansi=189928fc25b8 ansi256=66a31fd27570 html=94c99c9a140f
51-04/059 b210cfeb355ca92703eb5a7d51+04/059 input=3dbd041c8a93 vt=46c05b268911 graphics=e8b76a1b9359 history=e3b0c44298fc ansi=80563f330836 ansi256=dc1a4011688e html=aa6ca15fed94
52-04/079 567e6224445b47f639d6740652+04/079 input=6eb4f8e4532a vt=350a5e00a351 graphics=22f91ab97776 history=e3b0c44298fc ansi=0925fc7cb5c2 ansi256=45ee9ea10f8a html=fc626d1af828
53-04/099 36dfe5e3817a756a7761028053+04/099 input=db3717e615c0 vt=107edd2cc2a8 graphics=c34235f9e530 history=e3b0c44298fc ansi=af0374be4eda ansi256=151e18f23ddc html=74f0e0a24be3
54-04/119 28f266be513510780e5298a054+04/119 input=cea55fc507f8 vt=b574c0bff677 graphics=93af9ac5666c history=e3b0c44298fc ansi=5add5259e40e ansi256=6138ac10783b html=6694d7af35ea
55-04/139 77159aaa349724f6a346808355+04/139 input=6955544376f2 vt=4f1f8af871a1 graphics=f538e5cd130e history=e3b0c44298fc ansi=f2c8d68bc14c ansi256=6c4c3b4fbd78 html=abb28b5beb15
56-04/159 454932ee14333813f68147b256+04/159 input=b9a9ad2510b6 vt=8c8645285af7 graphics=3b4e5f278af3 history=e3b0c44298fc ansi=0b0a39ce76c3 ansi256=54414e73c0da html=879d40057ea7
57-04/179 5dc2da5983a46d4d8c04546357+04/179 input=211613aa2202 vt=c94fe03d96b5 graphics=d96a2ae371a5 history=e3b0c44298fc ansi=0adeddeaefc3 ansi256=9cc4ecb5bffe html=7cc5ca56a2d9
58-04/199 33b567344c5ba4cbb11073b758+04/199 input=58e91ff2f4ab vt=6490ae61b95d graphics=d2752175246b history=e3b0c44298fc ansi=63f461c41790 ansi256=3c1d924c1e80 html=30611d9fd7f2
59-04/219 98d41d64e511dc4f992f9ddd59+04/219 input=0eba9ec5a46c vt=1d18d28ac035 graphics=fc388d3d53a8 history=e3b0c44298fc ansi=680f2d93282c ansi256=2f45b31b9744 html=1ddfbe8755f7
60-04/239 a873589f7cbf01ab9771242460+04/239 input=e7f7c681f5b9 vt=0279ccd298ba graphics=81e51316a2a4 history=e3b0c44298fc ansi=7f4446d48723 ansi256=caa0483de38f html=c282e85e2abd
61-05/019 68d508ff98ffe9c97d49151261+05/019 input=f708f21d5048 vt=41bb0068b9d5 graphics=54d51f156f82 history=07dd8ff61a7d ansi=72c3abe84900 ansi256=9d5c3edf7855 html=4a7b2ecf0e1e
62-05/039 22833aa6ac5590fd5c51a10c62+05/039 input=85ab36e8b650 vt=efaa87c37a99 graphics=532ada5ceafc history=3f002ee29e52 ansi=17da07e9f85a ansi256=2e2edf5b0f11 html=28eb1294ac9c
63-05/059 f37316a5530d28ea4d38659963+05/059 input=2e2be67ca1d8 vt=2d832e81234a graphics=93c5f3db8810 history=26ad83f6ee57 ansi=49df0f3f3645 ansi256=f0b65aeb31f1 html=31cd90891c94
64-05/079 72697ed3d723a5e4e2bf127e64+05/079 input=ba87d248dd45 vt=b4b08d9512f9 graphics=34b65f470628 history=9114e0fa08e7 ansi=09a785da16ea ansi256=194216597b68 html=89f907ea5f80
65-05/099 b8128a9baa2e24f9cc2b10d065+05/099 input=e10211359c74 vt=3ceccf69da23 graphics=dda37883cced history=73a01cd06763 ansi=850eda258fcf ansi256=5dd5fa36a9d2 html=b3c3b354c29e
66-05/119 4f7d25dbe1b50ecf1ff6790166+05/119 input=fffb660dfb77 vt=4c267790e36d graphics=250e1fb7980e history=2f84702229a3 ansi=27896d56c106 ansi256=67417b228a96 html=baca43c0fded
67-05/139 c269b4f1d67c5238d12fabc067+05/139 input=11becbe9e073 vt=4896be991e3e graphics=b9946b6cbb9c history=d83501ac272e ansi=d665657c3a5b ansi256=f4e6bac4daf8 html=481b4b26e549
68-05/159 1ebdd92e38aeadf77e3d6c7268+05/159 input=13ccb02683b9 vt=641ab8e1a9f5 graphics=fd8edc008758 history=1e949032c82f ansi=1c055d639abd ansi256=c39256b8bb32 html=9dc8479b34b6
69-05/179 ffc342703ae6c3a8c4cd9f5769+05/179 input=391e22e966cb vt=1c6ed4e827b0 graphics=67ec83f5987e history=4c5309acfd04 ansi=133414fa03a3 ansi256=ac1eccd3b707 html=e4e11d09f7d3
70-05/199 cb964d13d6ed459f435eca6970+05/199 input=7eb6729857bb vt=d7257566974a graphics=fe1fbdd5b0b4 history=4c0bd02293b1 ansi=4f242a4aca0c ansi256=a7c99d8be3da html=e7d40e2c3935
71-05/219 945a552afa3fc038c0d0d49d71+05/219 input=ba08f58d01d5 vt=1cd8cd975688 graphics=f59bb471eb52 history=534f3354524d ansi=b3db0423a107 ansi256=2188a64e0992 html=dc36d8842b27
72-05/239 bb39be7fce9c2c1f3a7dd6a372+05/239 input=366f9db6155b vt=b075af8eef2b graphics=89b9e8b5c474 history=c162856ede0d ansi=6ab7cf4895ed ansi256=40d312f0e070 html=92927bf6ba6e
73-06/019 9f70eb84e027a0da12cf789e73+06/019 input=74524b6e33c7 vt=48a669c6fac9 graphics=9258c91bf1d0 history=898655683e17 ansi=4713ac9daf80 ansi256=67a882e6ad82 html=b911dde00978
74-06/039 fd1b4d60360d797d01dcf98074+06/039 input=65197226e07a vt=f6995273dbeb graphics=ec94ae6cc7b9 history=5362c829d6ad ansi=2e6a4fe4092e ansi256=cab88d1949fa html=e2ee10938c01
75-06/059 e957cf36ed0da231cc78173275+06/059 input=0059c87f2ba3 vt=aa1cd4936ce4 graphics=fa4b1bdcb736 history=8d74567c7596 ansi=47ddcf9ea936 ansi256=3cf60f5f6c0b html=76ba5fdb95de
76-06/079 ef5a1e45228ec8d02b4339fb76+06/079 input=d1e20fd8eb50 vt=9ec6d176dcc8 graphics=8183b528dbca history=4d405f4fb2ca ansi=9659e34e0243 ansi256=0edab42116ad html=2b36d393a76c
77-06/099 8aee61a050bf383a74a62a8b77+06/099 input=cafcb126860a vt=5afe741a2678 graphics=fac73a1bb510 history=13c0d17ff5bd ansi=f55dd08f48f4 ansi256=e644288fb538 html=685b92a736a2
78-06/119 b63b5ac60fb59413621ca13078+06/119 input=a80f65f5b0a8 vt=ee42a12d024e graphics=97f45805af9a history=967e9dfc2073 ansi=cd0494e91242 ansi256=1d6db9d74155 html=ecd2b64c1487
79-06/139 08d32c2a7d6a3d47faf8ad7e79+06/139 input=62d38f2be4a0 vt=238cb53ef640 graphics=f9e4dbc600c0 history=1a9c7f633db0 ansi=ef51adddf2f0 ansi256=7e7e85043c92 html=18ed59e5f344
80-06/159 ae180c731417adc39a3ac92e80+06/159 input=1cb1815e815b vt=831a04bbada5 graphics=7bd60ce8809b history=716ecc549fb4 ansi=97b20d9d7b63 ansi256=f9473ebaf756 html=8bdb2b2c8d25
81-06/179 50ecc3cc8de94af4fb6256e681+06/179 input=5badf3d2dff5 vt=c620f20feba4 graphics=1698c6765d18 history=f4624d43f8fe ansi=394a6010d7c3 ansi256=c0412c491438 html=aa3ec816effd
82-06/199 bcad1567aa6b13757337ca6582+06/199 input=d3d3d2ce734a vt=28cd61f9633f graphics=09f725b24161 history=3807f05bc93c ansi=bfef2232dc63 ansi256=023386bab8cb html=1af233b18eaf
83-06/219 6d9e62599ea93901fbb98bda83+06/219 input=8506dd47df97 vt=b148edd65135 graphics=19818e5dfbce history=cef46ab3f84f ansi=673db820b25a ansi256=912deffb9972 html=d56e75c605ef
84-06/239 12ad1caedd5346ab013bd93684+06/239 input=077726566d29 vt=064f0e868a78 graphics=cd062ea3471e history=3b8a6b0106d8 ansi=506bf9a5f620 ansi256=80c6f5141a3f html=d9fa0212e304
85-07/019 771e7f8f79ce9d77f0bb56ff85+07/019 input=fae29ee9e551 vt=4d8363b27bf0 graphics=e93052db1f72 history=a016741d0c17 ansi=fb6cbbd2bbb1 ansi256=b6407309d580 html=1904c198bc6e
86-07/039 031ed4ce8ac59a36ac7c136586+07/039 input=dc25e2be6a38 vt=f0b1efcfcfa2 graphics=50e4979362e6 history=493077d95eaa ansi=fe6fa23f8ed3 ansi256=a10d6bbfa9cc html=59e4d2e00aa9
87-07/059 2516663f39582c63aa21821887+07/059 input=7975bd5ebcd1 vt=fac6dce4c0d8 graphics=57703a717cd1 history=3f97ffdc2dec ansi=25965c7ad385 ansi256=3da98bce60a1 html=b648e177f0b2
88-07/079 3cd9f1f67cef906806422bdd88+07/079 input=9c6219207676 vt=c94ffbffb325 graphics=fc80a80a4994 history=c02df921f9d1 ansi=a5d71cafb48f ansi256=3c6df957f87f html=2bf30738dbc6
89-07/099 c3709b3f1a08717fc304d15989+07/099 input=92186125c91e vt=9e6e590d719c graphics=b9fe79beddae history=3f28dfa7b563 ansi=95707765409a ansi256=1bdc74a4465d html=f33078e2cc8b
90-07/119 9ca36d78bfa961ac711edb0790+07/119 input=8fd98cda3883 vt=1fbec962753f graphics=c37f447943f5 history=0d80f172198d ansi=f55cac729412 ansi256=bbc080afd759 html=2f9227221148
91-07/139 fea50cc9d78951ce47ab7b5c91+07/139 input=388a492ea7fe vt=bb6eefe94a6f graphics=5ad6c9e6e516 history=044cb3ac10ba ansi=0ffee86f12c9 ansi256=12f550934278 html=df8750ee768e
92-07/159 ac33e3c1365cc8c449a0d77b92+07/159 input=2d0089ab5f6a vt=034e8c8d8411 graphics=109355c3ac63 history=c359ce2d2381 ansi=4111ff4d3cda ansi256=16385f645c5e html=fe6a2200015c
93-07/179 92874af432d8106e7d39dd7393+07/179 input=9e4cb64f8a8c vt=1e5650773386 graphics=9a017a89f0dc history=591f5b1ff1ae ansi=b2cda00f5d7b ansi256=f31f5aedab35 html=653e213032d1
94-07/199 6a9cdfd7f92ce4e2fc62bc5d94+07/199 input=4353da204940 vt=f3b87f13eb10 graphics=71f7c96bfdae history=50ee391fa45a ansi=21971bfbc100 ansi256=e9ebfde84853 html=ad6f2f4f0ec1
95-07/219 40b3fb6542a9c48e6b1d5d0395+07/219 input=dbf5ec27883f vt=69598cc4d0e7 graphics=710c0213a1fe history=d693455d4f7e ansi=53c3b90f9274 ansi256=8a2a3ca793cd html=9ee083a32da9
96-07/239 10ecce8a3a41880bd86674e596+07/239 input=ee738b75ee7b vt=e8eb1c81e3f2 graphics=c9d2c2dc189f history=3064233b1b2c ansi=2da069a3b0ab ansi256=2652868cc89a html=70fad90a28fb
97-08/019 29e2816bc5d015ce2d23c05c97+08/019 input=ffb611ad4389 vt=e72fb0e18d1b graphics=0af58323e07f history=e3b0c44298fc ansi=eba47ed76a95 ansi256=61978201c3de html=c5f7b46ad24c
98-08/039 2a86fe7ff64d840cd856973798+08/039 input=cec6bf13be3c vt=3515ec5c5c8c graphics=b5ac885200ab history=e3b0c44298fc ansi=efc869104b50 ansi256=3c21d039ec78 html=ad915c491c57
99-08/059 51239ba60dc3b8f1b5078c4599+08/059 input=687fc086986c vt=f60a863259ce graphics=dae0356b61d7 history=e3b0c44298fc ansi=135df0896a7e ansi256=7b605cee5329 html=8d3fb3996cc3
100-08/079 abb48c671fe1388ddd3dbe91100+08/079 input=26b30a7bfe76 vt=3c80b0ac0d77 graphics=7ab6e8e4205d history=e3b0c44298fc ansi=9ffdabb3d74e ansi256=384c10e114b0 html=db675520568c
101-08/099 bcfe3784a4f3cbe24d417126101+08/099 input=85d377028faa vt=7258eb053a31 graphics=1b7d1f50bca5 history=e3b0c44298fc ansi=0f3c263fb26d ansi256=6302751823d5 html=59317cd039d6
102-08/119 039ca7a36109843550b4bbe2102+08/119 input=721048e0006f vt=8c18883d7799 graphics=933354e913ef history=e3b0c44298fc ansi=80e418ed9332 ansi256=6f9633182d67 html=5878d788176d
103-08/139 0e6735e9400e34df32a24bc6103+08/139 input=e89bacfc0b2a vt=2175ffd19d2d graphics=76585c8b0c85 history=e3b0c44298fc ansi=444b4cff6b95 ansi256=caf0f0407661 html=3adc8b865793
104-08/159 4cdce3dbee4325befd425faf104+08/159 input=6bcd5944fc82 vt=3f8142208b56 graphics=ac884b93caf7 history=e3b0c44298fc ansi=887116ca8f6e ansi256=b317af8348e6 html=29d4019bb2d8
105-08/179 005758f8650f3cec82710cfe105+08/179 input=5c4c5729bd97 vt=af526eeb4ae5 graphics=223826b2fa2e history=e3b0c44298fc ansi=8d1309edf72a ansi256=f1a71a58ee69 html=2ffd35213559
106-08/199 52482d634ba2b06bf34693dd106+08/199 input=219d070f7cd5 vt=ff2bfd155de5 graphics=edb68bafb771 history=e3b0c44298fc ansi=3b50eb64330d ansi256=624d1973d4c1 html=fae82782f004
107-08/219 1b3e53ed97faccd2061b9e26107+08/219 input=9a8b9ab14cf8 vt=6e6f6c767761 graphics=1d9ff4825974 history=e3b0c44298fc ansi=a02880b1f6d8 ansi256=2d8685209b13 html=7c47212ef248
108-08/239 c4ea1ea89908641b93e41266108+08/239 input=d5a0eabb673d vt=59a1e70c0ae1 graphics=7c4d6749fdab history=e3b0c44298fc ansi=ee7fc1249130 ansi256=827ebce60d16 html=60e96934c1e7
109-09/019 4c119ea37ab5f5aaf7ab50f3109+09/019 input=375c31d38e01 vt=e61ab6ec4c87 graphics=9258c91bf1d0 history=ae793708b2e3 ansi=9933eb508d02 ansi256=825a3a7b06cc html=dc8dc5491115
110-09/039 a1efea7a141d9b5481317d21110+09/039 input=51adeda97c8a vt=8538ff184ac7 graphics=ec94ae6cc7b9 history=3355696a7a17 ansi=8d7ca8687c2b ansi256=8104cf283c3f html=05130e0da4ad
111-09/059 a0cce6141ccb877fe5e71f53111+09/059 input=26704fddad28 vt=784b54585b46 graphics=04ecffba52a2 history=398a3fca14d9 ansi=7ffb8815309d ansi256=1e5a60233787 html=4a85047ed01c
112-09/079 614e9de8720ed8292a34242d112+09/079 input=a2c65542686b vt=95266b5f896f graphics=429dd0371fdc history=74dbda994020 ansi=5412731ac28c ansi256=626afcad4b76 html=f5f8ef6ba658
113-09/099 fb69e78cf4ccaeba35c42a8a113+09/099 input=63f82eef3142 vt=e1628289d678 graphics=b012cf49350e history=e653fd8f57b2 ansi=1990868a0a83 ansi256=154cb27c6867 html=8720031f8dc1
114-09/119 52f16f33c2b608d3d6b59394114+09/119 input=50f417492a89 vt=95ccdf0c4556 graphics=3c082a76bd09 history=eca74c726b29 ansi=25f847e9a0a1 ansi256=8bbc1364711b html=3110d4191b15
115-09/139 b9f02f6852f5de3b13640508115+09/139 input=f22701044a4e vt=7228dceef0d8 graphics=5016c8d979ca history=555cc174c81c ansi=d92b9305a595 ansi256=ec316e005b62 html=de0e7c44ca73
116-09/159 72b12cd005097c0ba898111c116+09/159 input=f4cde1fc68a6 vt=ca04021ddae7 graphics=44017697e035 history=b51ca289a2cd ansi=3537fc95a66f ansi256=bd90418c5f00 html=6ae5b29a5d33
117-09/179 06937b4778221356408d2ed2117+09/179 input=fb22f401fa59 vt=700c026a33bc graphics=889a00c22cfb history=f07dc27c1831 ansi=ab274c4be5dd ansi256=495917d23e1b html=d3f3e23f5d84
118-09/199 369339d7370f38fcc22a12b9118+09/199 input=9ebd3391a785 vt=3693180d540a graphics=8441eff04541 history=9f926ff96f78 ansi=4a7c3681294d ansi256=f9b30e3b20cb html=f82cf6f343ae
119-09/219 b9eec1e382e0500d5f1edde7119+09/219 input=7c79ac16673d vt=b9a4c0603935 graphics=a83ab7751bc5 history=a03bc237d484 ansi=48dc26e77ed3 ansi256=040865fea0e2 html=3b2fb2e87e14
120-09/239 c99a2183f2174d1e39502356120+09/239 input=33d1b8f46fc6 vt=5bf2f76601b2 graphics=d4f2f55f7ecc history=105ae31c67f2 ansi=c4ad351e161e ansi256=8ed3feb18879 html=c609fd52d6c6
121-10/019 f1b345ef33635fe6028f81b4121+10/019 input=4a773fa88d0e vt=e56acbaa3c3c graphics=f8979b697ae6 history=9a1d180260d9 ansi=b2b0a3acf112 ansi256=e99773dd4ed9 html=c3b1d6f9af79
122-10/039 bb0ee5ddb6ba0461e8747c48122+10/039 input=5a19d9d4c2d6 vt=7ffdb9e95420 graphics=896174966c8e history=091b178e1831 ansi=7d1e36e89a84 ansi256=e415fef4821c html=952d3c5bf21b
123-10/059 7b0a1d3c4fcef2b20317695f123+10/059 input=3d61fb352e87 vt=156ac33a85b0 graphics=60644c95d91b history=06f1f1fab2f4 ansi=a2d1a144f34a ansi256=6e2066d8c58b html=1a1175166ea9
124-10/079 9d002061162fa4fab0050bcd124+10/079 input=d5182a61be8c vt=cd5fdb02e924 graphics=309679508d19 history=5fa6d8aeda89 ansi=2a0e3196bfd6 ansi256=9e1147ef50bd html=ce8dea3d316e
125-10/099 3878530870a8fb56b8328017125+10/099 input=66f393c8e024 vt=2e7994bde84b graphics=dbc14a5ae241 history=04998276902f ansi=aee487949558 ansi256=c87b7581c162 html=619c397c3d0f
126-10/119 620d17d70aa0ae092bfe7fe0126+10/119 input=b49c6e9c2784 vt=c46e5f7f618b graphics=33cd5cd651da history=5c9911da4a8f ansi=6084136b1e33 ansi256=a33ff57d23c0 html=51a347687195
127-10/139 5d8a36f80fa538d941383259127+10/139 input=b1b06a0b58cd vt=b88fda26708b graphics=b9cd90b1ed9d history=41f382e35a07 ansi=01c25d2d4537 ansi256=9d617a7f0a07 html=5b2119c988ff
128-10/159 4f464ea644caecec04f35afc128+10/159 input=fbaf8971741d vt=19ec261f5b77 graphics=bcf25cdb2e51 history=c5cfe985bd1b ansi=4ae61c21451f ansi256=9c3dc8f71556 html=99d1313114bb
129-10/179 c60434e2aa9d7a64724ca147129+10/179 input=b02f77b5cd73 vt=5375dd4ed7f6 graphics=f591bfded96c history=c4fcf5031cbb ansi=500ee209d80a ansi256=ce2b80daad73 html=dbfc1a9f8389
130-10/199 b9f0bdae9c7a31f6ca8bcbe6130+10/199 input=cc1128412f8b vt=7e4d2086c5bb graphics=b4956c877d8c history=a2b67591b711 ansi=00bd358eb62d ansi256=f141b4f09b2d html=b15c9bf82493
131-10/219 14e56199cd1442fc6793d65b131+10/219 input=2347ed53f13f vt=0af90759155f graphics=b19cc5de1ed4 history=88d94c1e29e9 ansi=ad17609946ad ansi256=737472c30aeb html=ff561dca927b
132-10/239 8c43ab2d5bde3b2fda977ddd132+10/239 input=8a8aa55dce6b vt=7a75f8f03acb graphics=b5618c41bc19 history=5d74197f29fc ansi=e33bf0b866fd ansi256=43b6ad691359 html=2c6a65d1b030
133-11/019 c93975e62fac424f33e30dbd133+11/019 input=9265dacd75c2 vt=375101271ee1 graphics=f8979b697ae6 history=711a38708632 ansi=84ce9b2e5448 ansi256=f7d6444a0ec2 html=685d54b5cb53
134-11/039 d346876e1b164d0cd0627c43134+11/039 input=fa84608e0849 vt=2a74efb6ab39 graphics=5dbcfed44856 history=e862c7fa8409 ansi=0497214221c4 ansi256=329e82145d64 html=d523431dbaa8
135-11/059 01e960a0c2e2ff6e67700683135+11/059 input=55f99f6d98ed vt=2a5bd217b354 graphics=7cc33ba32eea history=f6afc9616658 ansi=23f55173e472 ansi256=e8d2f6e6ed2b html=e82979905278
136-11/079 1dc0f11f0abb3b5fc9f24e7c136+11/079 input=a9b3a0df8858 vt=7d9930235196 graphics=6919c4d26b60 history=c5fe90406ec8 ansi=829d8d678f5a ansi256=000d15ca2660 html=1664c0bc58b7
137-11/099 08d0c2c91fc7f7b8bc077073137+11/099 input=ae76386fd7d1 vt=9cd4bda7b6f5 graphics=d455141d92f7 history=ead2e3f30d49 ansi=82a2bb0a9bdb ansi256=91509db5578f html=8618f8ac0481
138-11/119 c25c0212819cece6d0639b16138+11/119 input=9af26788e7bc vt=a3c03f3376e8 graphics=15a3c905b21d history=481784c95062 ansi=bb43cb4d0950 ansi256=f2f5c846ddf5 html=a780738715d5
139-11/139 05f7ae1225aab0d0cf837327139+11/139 input=f9baf0d2fb38 vt=ab6a31624261 graphics=a221841874c6 history=4248d3856c10 ansi=46d0c42a80c6 ansi256=0e32105ecd9e html=e9c94b0050bc
140-11/159 0b421f3d3607eed3fdd06a22140+11/159 input=95a95c43643e vt=d046ac47c2f6 graphics=d4f6f0ba7eb7 history=1fc26a2b22ca ansi=56ab2524964e ansi256=ad04371dbbc8 html=fc00ae7bffeb
141-11/179 dd0db71df59ff3782d710188141+11/179 input=dcc8364da3f4 vt=2129ba5cc2d2 graphics=f865953d3b1d history=598bb57229f6 ansi=adca037af52b ansi256=47bfdd0b6b2b html=52341cfdd5cb
142-11/199 8f76f1ddbcb47375a2539363142+11/199 input=203eef9c539c vt=d90f5a5f35fa graphics=cb2ad40dabec history=a23d1435d01d ansi=1f57d064d798 ansi256=7175de8c5a24 html=4ef9a65aef53
143-11/219 82ad6598f848e6ed7ab84f16143+11/219 input=32e59dd96f51 vt=66a86a72207f graphics=d19ae5484f1b history=a0c79bc4d577 ansi=124273bc600c ansi256=0eaeecc77e90 html=2d84f0b34b02
144-11/239 581acb7b5585a2cb9127aabe144+11/239 input=9fa7f4fdcde3 vt=7a764cea4e94 graphics=1ac611e08f86 history=793108a49d50 ansi=dc3e80fe3499 ansi256=4bfe0f0735c4 html=d53adab71625
145-12/019 4fade3921f5735064355eec1145+12/019 input=0cd53f8dc866 vt=94283af4d7bd graphics=aa1966378332 history=e3b0c44298fc ansi=9635b13597ab ansi256=9020c0176325 html=b2744def1bed
146-12/039 4752e78884537c49b3a981a6146+12/039 input=a4adb8bd74ff vt=1e4fa3c28868 graphics=446b136e5620 history=e3b0c44298fc ansi=846ae78c61c0 ansi256=61463b656f85 html=c3fe542cf614
147-12/059 8d24a113e07ffe7f2ee85d92147+12/059 input=8e1743411c94 vt=f2e40d527f1f graphics=383509aa2748 history=e3b0c44298fc ansi=e43feca44dd4 ansi256=5592050ecb33 html=ba5853607654
148-12/079 b664d979cc6ff5402f46feb5148+12/079 input=24b7b3927733 vt=ca5d80c350c7 graphics=adb60fbc77df history=e3b0c44298fc ansi=54cf7d6a19d2 ansi256=e8bc1048d1cb html=8720cb8d4748
149-12/099 71a4e7544cc95fed335b866a149+12/099 input=084e6637aff7 vt=5364ef66f04e graphics=8aee9666cf7e history=e3b0c44298fc ansi=3c9190df845e ansi256=df24c0122682 html=43f2d2763a3d
150-12/119 f3e962c48f6477dc9e36cba6150+12/119 input=dfad7236783e vt=b47b5f66a92f graphics=fc1ca2755ec5 history=e3b0c44298fc ansi=28f7789859cb ansi256=bfe43afcf74c html=7a25e8488c73
151-12/139 88ad314b543b01991001d0ff151+12/139 input=868d9b85b00d vt=b35476bcaf77 graphics=71e72390b15a history=e3b0c44298fc ansi=7a113a99cba4 ansi256=154812340ca6 html=bdbe756ad0eb
152-12/159 c496c6f531b311b533c5d8dc152+12/159 input=079a8d8cf303 vt=d5c21fc98ebd graphics=8e59b761a886 history=e3b0c44298fc ansi=633f2c29a069 ansi256=0a5d8a4bf2cc html=b5de688f4e37
153-12/179 902d77ceb40bc233976eab25153+12/179 input=b04504a5e95e vt=dc59f7f4f179 graphics=0c74926a3adc history=e3b0c44298fc ansi=6616cc37f757 ansi256=8bc4de6a188b html=729d8e8ed02c
154-12/199 ae45efdbdedea0732816ddd9154+12/199 input=087381b37012 vt=2dfb9fe9cb33 graphics=fb30a203819e history=e3b0c44298fc ansi=0ab48534e4f0 ansi256=376f1c085a06 html=80424fa73a56
155-12/219 a9b16863b78bef550c8f3a45155+12/219 input=1c3f8730674c vt=af87d933c49b graphics=28a7ba5996a9 history=e3b0c44298fc ansi=2c88572f8243 ansi256=50eb8105b067 html=618f932e30bb
156-12/239 42f9034b8b4fd71772b18bb3156+12/239 input=01426d60b04b vt=b39a82a17c4c graphics=3a167d043f4a history=e3b0c44298fc ansi=e63cf3dfdbc2 ansi256=e5a6efa00e87 html=1a1101a850a3
157-13/019 ef8a3432b61607340356a764157+13/019 input=7520f8daaf0c vt=acafc9adc02c graphics=f6ba63ec3717 history=46adc8d8dbc3 ansi=a96cee0c7c56 ansi256=1ff37de7ca5a html=461dbdd7849b
158-13/039 4e823b712c6aab07bcd5764e158+13/039 input=0b6c937d49bb vt=f0da4cf5bffe graphics=80775244c49f history=a68772b5b2a4 ansi=a605a2ddaaa4 ansi256=6c548f01ade8 html=2be43a85cc1d
159-13/059 90b7e616d2c528faeee0f72b159+13/059 input=73c036bb83ab vt=cccfcabc9883 graphics=e654e9345138 history=fe83f6679c59 ansi=dec1eee5f6b7 ansi256=46df57dbc15f html=f2bd74cccefa
160-13/079 b1330a7079b795346ee9e317160+13/079 input=1740e9668bd9 vt=2af93a316eea graphics=3c8abf2d09db history=59798eb0f0c0 ansi=c3f28ae5b5c4 ansi256=e17cc886a56c html=86e264ad48ff
161-13/099 9f0d10089131edf34cceb0a1161+13/099 input=8bee21358f91 vt=e5a61a289e0a graphics=3bf53336708e history=92cf7dbf6937 ansi=3162b5f25c5f ansi256=f762ea238db0 html=95aa64fdd24b
162-13/119 069d5dc52bcfba2eaa2211bd162+13/119 input=4a7587dd0528 vt=a42eceae253a graphics=f3248511fb51 history=43d954a57008 ansi=22700a2fb762 ansi256=ab2e8af6974c html=33a564524571
163-13/139 08b97ef26faddb637a424bef163+13/139 input=a013d2d99b71 vt=c56c6570ce4d graphics=56cf16bd1b92 history=2ed23713a723 ansi=09aebb4d1635 ansi256=1c5bb54127d9 html=36c58cdf4992
164-13/159 c29b028480ce1c097e8c3066164+13/159 input=671dfaa83917 vt=d53289c06948 graphics=d145457d4b59 history=80fa71b1a3aa ansi=d40af80aa84d ansi256=b5417d3c6341 html=e37a3eccd6ce
165-13/179 85d6cc0d0267ce57c4f438d7165+13/179 input=4ac1c3073a32 vt=8dc458197d00 graphics=e8ea9c343f0d history=7d8a9ea0b656 ansi=64beed089e47 ansi256=1808932f9729 html=f4affc600b08
166-13/199 84a14ed35e312f14e0c4d220166+13/199 input=8db1eaec3f54 vt=5c71eaa36a21 graphics=c27ebde9c961 history=b19a73a76ecf ansi=b8592ddd4d3b ansi256=00729536519a html=39aa8e2fbb44
167-13/219 8382c4d6025f22cddd967535167+13/219 input=9fb709c6f4f5 vt=5887f955f492 graphics=f81762265c3c history=ebf71b617ff3 ansi=580afcb45172 ansi256=ae3d6515c35b html=5cd3d7c38131
168-13/239 4e3ac44cff6dfa7d7a843378168+13/239 input=607893ccc66e vt=9b45c6f4ad16 graphics=57aad1c476be history=7525380830a1 ansi=34ebc3bbd92c ansi256=0403d973c622 html=60dae1c93eeb
169-14/019 747d54cdf75a492242809318169+14/019 input=a7f334c12c30 vt=9bcdf21a28d1 graphics=81c725928397 history=2385a3e8dab8 ansi=c0c9f7a64341 ansi256=b31486c31b86 html=35708e80da60
170-14/039 e6530a9282bd6095e15a9677170+14/039 input=cb163ae3c433 vt=5753f4daeff1 graphics=d7c6ebd7cfc0 history=587cae73034f ansi=2d4925a35af4 ansi256=f66845c5742b html=baeb6bcefb51
171-14/059 715de56023e1afc30c1feea1171+14/059 input=f56d76937fd0 vt=57b2f629970a graphics=8a7d860c2c19 history=2fbcda1cb486 ansi=c6cb6b834b4e ansi256=845612b63a58 html=9252e3a88f4c
172-14/079 f5c6253e95d471ccf7892526172+14/079 input=f33604d23f28 vt=c974e326a90b graphics=6f6c28b5e14f history=9c6e93bf5ae0 ansi=a264f3287c53 ansi256=aa0e7995674c html=678f55e2b870
173-14/099 09063bb10e3e19d067c9c85c173+14/099 input=66e2c12b7a2c vt=21ae28e601f7 graphics=c841084c011b history=77fcecaf9198 ansi=f88e07c8b8e7 ansi256=f61593ae5173 html=b615aa206946
174-14/119 f8753c5d5010cd747e5dcc31174+14/119 input=2423dd867693 vt=260dca79f790 graphics=13c1d848ef7c history=0578cc790f11 ansi=d6cd6e0d3a39 ansi256=a7030caa2248 html=0248bc83fd1f
175-14/139 8a726baa028acc349f76fcb5175+14/139 input=6bba00dd2011 vt=a272f823ab24 graphics=ff9f2a7413a2 history=e88c4115b82b ansi=219f25d864eb ansi256=a895895e4810 html=3f8fc72b3e73
176-14/159 6707de5fd29ec469ba8913b9176+14/159 input=bd6974df946a vt=04ddc0b7cc5a graphics=d0cc3cf7f292 history=115133c655d6 ansi=f5a8ffdb271b ansi256=18c35ff238cd html=b9c2a5885b26
177-14/179 3914c9045ccb2d16f6dfb386177+14/179 input=37e67a5d9bbb vt=0fde96b6035a graphics=d7a2abfae087 history=e67566a79d14 ansi=527202ca46b4 ansi256=8a82a2201ac1 html=39eb2a61fe24
178-14/199 f5992df3d18c885bcaab4496178+14/199 input=e37a2b467fbe vt=b24e698bc457 graphics=b8031e6234b1 history=6c6cd77efa68 ansi=bb95fe893d2c ansi256=b167c3b0e86e html=5ba24470430a
179-14/219 38e1a9fe90723b701c438464179+14/219 input=1029130bfbb3 vt=e88b9860fbf3 graphics=334fcad630b4 history=601f1eaad212 ansi=34f9eee0f681 ansi256=a7a0e8e22cf3 html=e8f97d2a8ab8
180-14/239 c90fb86719f7e4613e3720c2180+14/239 input=4f4b33115d02 vt=665ba03c5b8d graphics=bcdf3ceb7d32 history=64972943269c ansi=abf6d0a0365e ansi256=568e79b90695 html=b26a8767b60f
181-15/019 95e07748c709fa34a80ceff7181+15/019 input=adebbbf2b67e vt=592cebb0eae3 graphics=9258c91bf1d0 history=9f7f72048c7e ansi=a847879b9e08 ansi256=7289d4ca24b0 html=c81ae1f026d5
182-15/039 17f763741791d1ce05af5d23182+15/039 input=2f24c044f13b vt=9b88bb5525f8 graphics=7273f3c7ea47 history=10b4c3487308 ansi=d813c264ae04 ansi256=513731bb2435 html=832e48b619ef
183-15/059 91afaa9890df8d7e1704a824183+15/059 input=3f7f0171fcbc vt=f9c33f6d70ca graphics=65b90ea66aa7 history=61984d2b07f3 ansi=11c2dc4fbbdd ansi256=a295c8d95c3d html=74a231c8abae
184-15/079 f7b444177e7de8fbd6ffb68c184+15/079 input=73c002f7f158 vt=24e15581eb38 graphics=3cb55010354a history=d1eb9f880a9f ansi=26e7212c03ac ansi256=1c68f8acd6ac html=d6b96f3a1124
185-15/099 c1a6b419a58119e00553b73b185+15/099 input=d0d48ac2b495 vt=9a76e08324cd graphics=ed4caac777f5 history=0c0c27929ec9 ansi=82c96808d0b9 ansi256=f675fc6e8262 html=73ffc8cb16bc
186-15/119 e087eec2596edb2fbb67b309186+15/119 input=3fa81ee4d3ba vt=a81be1aa206e graphics=ff117fead386 history=20d00a7e251f ansi=3aba1781bad7 ansi256=07e4c09ffdb7 html=6dd9ca74de99
187-15/139 2f6949b8d82d85d0ed0e1945187+15/139 input=68408fbbf5ee vt=a32e7bbf0c27 graphics=0054f2fa69dc history=580f23cdf9fd ansi=ac525261d78b ansi256=b10a40001689 html=8959a3ae5b86
188-15/159 d870e1d84bf822c53958e42e188+15/159 input=ba1363213435 vt=3619f3845be9 graphics=78ed8fc1091e history=b7aa7e1d1cad ansi=28499c397587 ansi256=89ad14bc135b html=1d2ae39f6ea4
189-15/179 e61ad13af00d508f72ca02e9189+15/179 input=33e641fc5d55 vt=f64b9094c4dd graphics=ef3c8c1e57a0 history=186362c6d3a3 ansi=4b9d9655854c ansi256=a1c9511e4cd2 html=cdc0d8cd4e2c
190-15/199 c2e3de3f26a36097e8df792e190+15/199 input=ef88153e80d9 vt=0801d3286cdd graphics=2d4906246230 history=fd3b0095a05e ansi=00e0730b7f8f ansi256=4324a4e945bd html=504e8fdfd696
191-15/219 6d50c5b64eca9d2ece1e3556191+15/219 input=fddb2208db96 vt=1369dc45a440 graphics=b012b26b3b66 history=2febb7f5b494 ansi=1413b3804af6 ansi256=c0d3e8b8786e html=cfb271a64a93
192-15/239 6c7b58a0ed8591a241ab438d192+15/239 input=6a6b1380bfa1 vt=0ae81863dd42 graphics=701820e5764c history=4f15a73b2b68 ansi=303f8cd3cc58 ansi256=520deee2c650 html=c16b2ad7d817
193-16/019 4314babccb7675abd6328c32193+16/019 input=86c2dda4db03 vt=6d7415e4ab74 graphics=f8979b697ae6 history=e3b0c44298fc ansi=76a6fbc5b6c3 ansi256=ff3164ac5487 html=12bb8014b393
194-16/039 3e6ee1b339dab4ff5e0c8b34194+16/039 input=55ed57bbec1d vt=c7de0211b8a3 graphics=982379a6cc3d history=e3b0c44298fc ansi=0a5c39595e6e ansi256=d0cb3aa4a078 html=882f254a57bd
195-16/059 1afd8504d6a0be4d6cc9c3c3195+16/059 input=75c0a5c47c7c vt=41df5e7c69c2 graphics=842a2ffbda7d history=e3b0c44298fc ansi=7e4f99dcb027 ansi256=c9183d6491e2 html=aaed4ccf4e11
196-16/079 50f71b7a9d7c444810cf1ba6196+16/079 input=e47d941b4795 vt=29818752a1ca graphics=83bad9ddc481 history=e3b0c44298fc ansi=1c402472c1c7 ansi256=0b8c9fbd2c3c html=da5f12987565
197-16/099 65a1c2e6e41adcddbc510efc197+16/099 input=1d5b3f836ac9 vt=fa20f6be77fc graphics=a76562326d86 history=e3b0c44298fc ansi=56aac95f1834 ansi256=fe63446dcca4 html=9ba9d95cc8dc
198-16/119 3f7c33fe85ccde2210b37f8f198+16/119 input=3732e6080846 vt=79f64e3b5554 graphics=14f68a7bb6bb history=e3b0c44298fc ansi=cb0bb8b4fadc ansi256=afa479443df7 html=74a9930b54de
199-16/139 1b47397842763e30313e66de199+16/139 input=1c79946f3ea3 vt=c45bb228fa62 graphics=2403dce32ba9 history=e3b0c44298fc ansi=1ca0a48540d9 ansi256=1096ad83e268 html=53c873c508f3
200-16/159 3d9b4904b96244df64051cc7200+16/159 input=b2687f8c50d3 vt=1501b13122dc graphics=3c87413b9ae6 history=e3b0c44298fc ansi=34725ee3e966 ansi256=f85d124e4f37 html=cb92bc348ac7
201-16/179 60ae20b4cabf7c1a02192010201+16/179 input=e6f371d2288b vt=f22a83e34a23 graphics=1d16a3c1ae70 history=e3b0c44298fc ansi=1e5b0b8d3682 ansi256=a80b1cb97d9e html=6ed1d0943b74
202-16/199 210f0c4ad73131d2b465b362202+16/199 input=ef6ef7381c1f vt=e6c36ee8cb16 graphics=629add49f562 history=e3b0c44298fc ansi=d8e1c77f2871 ansi256=5118043a76e9 html=182382bf5aa1
203-16/219 4b62676c69410e9b6f9d8f26203+16/219 input=a70b8d880419 vt=f6f6b6285356 graphics=379bd66ce1f5 history=e3b0c44298fc ansi=c9a98c855aba ansi256=548576b0b5cf html=c1ecafe6cceb
204-16/239 72f70f009e426f88b33ebdae204+16/239 input=e318eee4b6f3 vt=39841be2f7a7 graphics=d1fb1b1764e1 history=e3b0c44298fc ansi=d33af6657153 ansi256=a292cd0f0bc3 html=9f12c4a9c576
205-17/019 1a06602479d8e795ee95c965205+17/019 input=58c9a4153140 vt=324b438d3711 graphics=f8979b697ae6 history=711a38708632 ansi=5c9302e7cb6b ansi256=85a7583c5c6c html=d1cd396bd85c
206-17/039 c7e7eb54ee63d9e7e23ceaca206+17/039 input=db579e65ea7d vt=6fbfe2c1e929 graphics=5dbcfed44856 history=90f1132b4c8b ansi=d33d277dddb9 ansi256=877081d93305 html=bf1412d87fde
207-17/059 51c34ba1a80d55b1f9ae42fa207+17/059 input=f1499c3938fb vt=eed0360845e2 graphics=e7bc26dbbc26 history=c11561ff594b ansi=fe2e1e877cac ansi256=d77c223b95c9 html=91f0252e84a3
208-17/079 d5f10d70e10e0e87e54ac6f3208+17/079 input=9ec0bad9b8da vt=854ea5835b4c graphics=4e43c7db5d2b history=86f74a48ec8e ansi=233882d7d87d ansi256=b333d4c639b3 html=87008431833b
209-17/099 0a3784787eb2a97cce6c8309209+17/099 input=b1a45d5c094d vt=fb72368bcf60 graphics=7b45a01a7c43 history=864baf9e2a68 ansi=c5171a082201 ansi256=19ce8af4292d html=808649c8f7b1
210-17/119 7ccd8bedfbf26111e264baa5210+17/119 input=630c816a56f6 vt=7f3660b85dac graphics=5b2757212ce6 history=b1f20dbcbf8a ansi=137fbfd28076 ansi256=13c827cb60a9 html=c67aad58b8ae
211-17/139 f028c427efd1ce9c0b9828d1211+17/139 input=22d78f18ce2e vt=ab7b75a6d8f9 graphics=b437e11b41ee history=ad9bf3567e67 ansi=4b9c15d40677 ansi256=cc3881dfbffd html=8e9e0016dcd7
212-17/159 fb8b3eb57ac4186345d52918212+17/159 input=4ef271e495f0 vt=d00fe585dc54 graphics=6fc51315d33b history=d0783031468e ansi=e2224565fe65 ansi256=45f3942d9b49 html=b07e484d1f80
213-17/179 1c7da7757137c15d7a05d3d4213+17/179 input=e9b418a8b2ef vt=24199de84f03 graphics=a0cfd961aa4e history=4557d790c7b4 ansi=fba711ad72c5 ansi256=a9694cf6a10c html=ddb0554e57d4
214-17/199 55b35801df62b3250963613d214+17/199 input=61ca70a2bf80 vt=b1839e18ae6f graphics=92f8577c9b42 history=b81d21bcc4d5 ansi=6c5c1bb9cad5 ansi256=406444ebbca7 html=c85efa4f3290
215-17/219 1cb11bbb2c5dd8995094be53215+17/219 input=ff5c94c9b013 vt=5d22d9894727 graphics=7bc5dede1a89 history=4b4ab2d37875 ansi=dc67081dc05a ansi256=95c664bbd051 html=3a1923f73eb1
216-17/239 6a146a19d7c534c4766e98f8216+17/239 input=8cb41999a222 vt=dc320c39f15c graphics=7de85cd30f7a history=f0da9faa34f7 ansi=b53f7cb0427d ansi256=23ef37e00200 html=43d304aed60e
217-18/019 a1d2576637f54892892ea0b4217+18/019 input=1a8fb352acf4 vt=8c78c5a6e699 graphics=f8979b697ae6 history=cd2c313ff542 ansi=2a1160b2c9ef ansi256=8c5b08c915f6 html=2bf2911efe68
218-18/039 4415a2923a28b75a5aa0dbfb218+18/039 input=120fd08d580e vt=9d25a6b19337 graphics=896174966c8e history=875839281971 ansi=e78d4972dd5f ansi256=93a1db68bce5 html=3175a85eb9b3
219-18/059 2bac49c23f1c09f170c68dc2219+18/059 input=82098b093bfc vt=6c75370c7db9 graphics=207a60bb91d0 history=24174fce0b1f ansi=66d2d608a1f1 ansi256=158b0e0a39ec html=7dd3e682b17a
220-18/079 eeebf8f57f35ee0b110fc200220+18/079 input=cbeb78d372be vt=d27386b7d77b graphics=7de8d4796cb6 history=59795806ccc0 ansi=03e7a153c2ee ansi256=0b42ab8e910c html=089bcb7a902c
221-18/099 e3673a14664b853fa9613c64221+18/099 input=fe6eb5467cf1 vt=0784720cea47 graphics=e25a6167d75f history=1d9cfd1abb4e ansi=75bbd8201a08 ansi256=a34e0ca1feb4 html=f63a6dc3a8dd
222-18/119 57aa1250c9bb46869c8fc1a7222+18/119 input=95f0f611f332 vt=d017ed80bcab graphics=2049bdbbab3e history=a63d9aeb1f01 ansi=94ba30222542 ansi256=aa123dff5919 html=9ef446e144ba
223-18/139 abaca7067643db7db4dfe105223+18/139 input=3c2f99ffc023 vt=75e8e55898a9 graphics=f0595f3aa950 history=9d638c447b01 ansi=fa31decdd13e ansi256=6b7d5c6d8d68 html=d72827d09492
224-18/159 6e878b08b5635eac7ab9816c224+18/159 input=9ad591a6fb7d vt=4269793feb5b graphics=310714a28461 history=4758ee28b6bd ansi=91e9125972f8 ansi256=797e0afe0aee html=2319778b4656
225-18/179 031a000b34a4ba3bc6cedc53225+18/179 input=4cb34afc6104 vt=0485fb01b5dc graphics=145af612aaae history=e3bf8800fc5b ansi=ac0b90d29af0 ansi256=6f5f308aa309 html=3ac541d9babc
226-18/199 c523b55eb720c065fc6134ac226+18/199 input=30c450be5b97 vt=13406cc1f87e graphics=de90792e0729 history=241a96bae4c7 ansi=fb45d99a1b40 ansi256=a895d173ea7c html=169bf57f5be4
227-18/219 0f367277325b630ce5bc634f227+18/219 input=98e3ba6d672b vt=5786a38e5eca graphics=d73ed6f6b01f history=679dde0ae545 ansi=45503c8e4ceb ansi256=5e823b3c23fe html=da83ebd9c28b
228-18/239 e04b873c6820a46bfd2f4873228+18/239 input=4cdc68b810b1 vt=11f8526bd447 graphics=c934b313196f history=5f8e6cd1474f ansi=a4e37289b509 ansi256=d17b781bf646 html=d9facf5ef080
229-19/019 2db955914f2e068e72cf8dfa229+19/019 input=f025072611f9 vt=98568b096752 graphics=ceeffa9ccef0 history=223962168d6a ansi=982272b5b3fe ansi256=e8fa54fc8107 html=b4c79949091a
230-19/039 ec344560f2bb7de5f25fdb78230+19/039 input=a0fb77925963 vt=bc9062ea2ed5 graphics=6bbb371766da history=b4f46e999dc1 ansi=5ea1a0292697 ansi256=2945a8344189 html=67aa33fe168e
231-19/059 d1a41ae321f1449d256cf19d231+19/059 input=3143a584229f vt=5cfca7c8b962 graphics=a0f8cb27ebae history=bb35f1365c5c ansi=7fe21ad4ea22 ansi256=8c0a1fe0ff92 html=38ad5252ae40
232-19/079 8faf99af914b67a155d5ec77232+19/079 input=4d3dff9e2a08 vt=98bf07c97ece graphics=00fce6dcd131 history=a677db84e2e6 ansi=14ec6eb04e0c ansi256=3ae2236e1d07 html=d2988f43f0b6
233-19/099 4e1d07972fad7ea30ae47405233+19/099 input=a19d75d8d10d vt=650ec28e93e2 graphics=59ddaa7408c9 history=9d586b3ecfa3 ansi=87ba403a3b61 ansi256=14bb2fab1628 html=10230866f668
234-19/119 25c71afea29fbd715e2a4475234+19/119 input=dfd4382938c3 vt=800f59356c9d graphics=4e3403b66904 history=4a12e0d293d7 ansi=c06123578fca ansi256=14e2b9939b37 html=2063bd042d4c
235-19/139 c6aa86c0ecbc79508ca55d21235+19/139 input=d9daa2a5883f vt=4da1fe870181 graphics=b6b22e3b11c4 history=fc9604300c0f ansi=b45b6aaefb3c ansi256=3763b0de69f2 html=9fb9f7ad76a3
236-19/159 f4f99d1ac2eb88ec22a12895236+19/159 input=45fee457c34d vt=c150ddb3ac4e graphics=49f24bd1c839 history=996c5b447767 ansi=dbab6aaa9d86 ansi256=c3a8bee718ab html=f9c6e7a7791d
237-19/179 48e52a38bcee4b40556c3ad5237+19/179 input=3f763216e7cd vt=ea4eb51b5f00 graphics=fe3c10d6141b history=d4d85159b904 ansi=01a5e9d16446 ansi256=dcae4df49cdd html=3fd07b41ddc0
238-19/199 0000d0003982f1b02a05c031238+19/199 input=16fa624597c7 vt=c9df47e68a7c graphics=9dd86c09229e history=5142585fde71 ansi=f98e9a365f26 ansi256=89d119043450 html=e95640b13639
239-19/219 8a3fe5821bfca2452396d384239+19/219 input=5db9cbb2203d vt=6af15b8cec32 graphics=bc944b4862e6 history=9553e7f99699 ansi=2554dbc19ef5 ansi256=f147b4cad322 html=b03435926fa9
240-19/239 f80259caca42e4bec5999fbd240+19/239 input=ff65425ea000 vt=14e5cf5f064a graphics=786652c8dcaa history=93b9446a5724 ansi=3e8b96b5b855 ansi256=c35e2ebba309 html=711b0093e774
241-20/019 3c776bd6d460be5f6bcd060e241+20/019 input=16ab1b41f873 vt=1499bc214fc5 graphics=9258c91bf1d0 history=e3b0c44298fc ansi=6e012cb0dccf ansi256=da37e6c9d339 html=1e5a56704b1f
242-20/039 ef65b757bd137499a352d5ae242+20/039 input=7fdb1cd71af0 vt=b0db232b4e0c graphics=ec94ae6cc7b9 history=e3b0c44298fc ansi=3119d279d44b ansi256=53b0a1780247 html=52d553f534aa
243-20/059 1cfcab4ffbc08c619e97bcd5243+20/059 input=97bbd10bdc02 vt=4072b59cc2ed graphics=7bdd0ed29a7a history=e3b0c44298fc ansi=fe617dc64f1d ansi256=a5be42706dca html=f89b539d3cf2
244-20/079 8879e2856d1a555f07aa60d7244+20/079 input=4643c53e7d5f vt=258eb8d27202 graphics=484b3575b9e4 history=e3b0c44298fc ansi=b58678e2d51e ansi256=f1a4cbf04a19 html=c0ec4c442871
245-20/099 e16919d7e8c9f20f7dfa5956245+20/099 input=5c6ba398d86c vt=b3e2901f9ce0 graphics=3a68ef622ce1 history=e3b0c44298fc ansi=24622d01be50 ansi256=453ef09e3e72 html=09a56a97c1df
246-20/119 cb7f9cf61ef176f01706ac77246+20/119 input=bf82e477a33c vt=127461ab7faa graphics=dc64f3a0bcf8 history=e3b0c44298fc ansi=811ab8b1df46 ansi256=1fc38e82a4a2 html=69239da06710
247-20/139 f9edefe5603a815455b563ff247+20/139 input=4713957fa737 vt=25e0887161c7 graphics=3bcd0d1750d2 history=e3b0c44298fc ansi=0e872d556857 ansi256=2f37f4d66894 html=ea55b56c71d7
248-20/159 cf8862d058a774e0fdb18628248+20/159 input=4ae9c4eeb18a vt=709bfec3b6fc graphics=793c21562ca1 history=e3b0c44298fc ansi=ecb61bffd21e ansi256=ed97a1f1aab9 html=2375703500ae
249-20/179 abfad109898597588888b96d249+20/179 input=c7321f26aa4b vt=b2f88ab421ac graphics=6d505782c178 history=e3b0c44298fc ansi=e514cec2d55f ansi256=2f05ce045a65 html=e304819dcd51
250-20/199 a619ae4048d75c8eb123bc03250+20/199 input=1e64f0e712cc vt=459e975efafb graphics=0f85c60d8bcb history=e3b0c44298fc ansi=56387c036e8e ansi256=bfeda84d3504 html=a48d40ca4f47
251-20/219 e97c8dda4681c61c2597a6b6251+20/219 input=c61722782b3a vt=9190bfc820a1 graphics=f067ec496b5f history=e3b0c44298fc ansi=45bf0573bb99 ansi256=6cbb9c7975c0 html=3b23062ea98d
252-20/239 d3c1276233a20ff99b540e84252+20/239 input=c65e79b596b7 vt=d3c8edcf5fd1 graphics=a3a95cd20f28 history=e3b0c44298fc ansi=59e10a802b95 ansi256=dab2ffea8d09 html=c8c701b72531
253-21/019 357ece3eab75324d3823a6a4253+21/019 input=6d8b599454bb vt=e50e4850cdce graphics=9258c91bf1d0 history=6ebc4b61f2b4 ansi=d14fad767c53 ansi256=9e4839c11686 html=518eba74c84e
254-21/039 fe4501bedc7017bc40ff0509254+21/039 input=2f3792505a5c vt=3f8418dcf338 graphics=edd491a142d6 history=f505b2de2e1a ansi=9f4b37c1b289 ansi256=b0c92a0cf22d html=fa2697e6e19a
255-21/059 c97dc13dbcd996b58361777e255+21/059 input=50ba70575923 vt=596598247f57 graphics=174ea50ec6ff history=2cde5b0f65b4 ansi=11d6f5602c6b ansi256=3fa666485317 html=41b4c9987e4d
256-21/079 478d3efcfcca35aac31016e5256+21/079 input=1a42a368e14e vt=3be5c7a9966f graphics=c426645bbdd2 history=dbe1817e0470 ansi=ef4d959165ee ansi256=07ba166dcf3a html=c9a40672ea7f
257-21/099 3311dde300dcf85626edb8b7257+21/099 input=63df54056256 vt=b295b0f8bf2d graphics=36e802fe6bff history=22e67a9b0953 ansi=1a30d1904101 ansi256=d0d28a777232 html=ba2d6607611c
258-21/119 67ff6fbebbb9976f9f5191d8258+21/119 input=79df89b8fff0 vt=0db1c329e0d3 graphics=c8b780d37f64 history=ab7add1cd086 ansi=2cf9f805abf6 ansi256=3535c3153101 html=7d7915391dd6
259-21/139 034216a3e7d38b221d5a8811259+21/139 input=ea612f912526 vt=c752acdac1a8 graphics=0227de479c40 history=b10111c570bf ansi=72518d3e245e ansi256=029947f1bff3 html=dea59c047bbf
260-21/159 adc62b539970ad3123cb4175260+21/159 input=aeec6f11002c vt=ac7d2948b0b1 graphics=467a390aa711 history=24ec315d181b ansi=fa7beae868b5 ansi256=fb0946d83c29 html=06e70ca42d9d
261-21/179 0323505afc602891ba38d7ac261+21/179 input=24c60e60e3b1 vt=947c888b5fce graphics=efb40f7c49d2 history=798d584342c8 ansi=df547f10afec ansi256=5bbbdd3ca038 html=1eeb28e01a3d
262-21/199 2c8eb6ab3e644c91102d47c5262+21/199 input=547dccaa57f2 vt=d641d1cb2344 graphics=ff664e7569f7 history=2fa0eac3eb0a ansi=c153660c3195 ansi256=de9744c0df8b html=cc94e437c027
263-21/219 c88b6d036e56dd9bf2772e84263+21/219 input=580f2ee8bf6b vt=c24cc36b68cb graphics=b37f93b7361c history=e6d0f07fe46d ansi=1425654efbe1 ansi256=9f0b0970721b html=8432818c20c0
264-21/239 1541f980765b4f40cd846615264+21/239 input=f1652e1ff7e7 vt=0d7501b75864 graphics=47ada5c8972d history=de469d69d99b ansi=bacf8fe6257b ansi256=d568d80203ef html=dfe930a2b881
265-22/019 6fc626ac7796049f3457a9a7265+22/019 input=01ba17ac85c4 vt=496cb010d953 graphics=f22af68f3b72 history=b7f0f7e99584 ansi=6eb40193751c ansi256=1c451df21b16 html=827985f38ddd
266-22/039 e9214d74742e6ab1a1c8baf0266+22/039 input=42f3c147fdba vt=a3c945d1206f graphics=ccb9f1f8aec3 history=c7e0e31fcf0e ansi=d90cd8db8990 ansi256=2f717b9573f0 html=2063a9c75ac8
267-22/059 72e63b2a0100e4153851a23d267+22/059 input=b5272cf6b2c0 vt=d0e9e33e4c1d graphics=e6e24428355e history=aaeb10ce7c44 ansi=c85a689382eb ansi256=bb35fa6ad750 html=bc5cbb51abdf
268-22/079 9b1a8ebe1c432db2fedb68e3268+22/079 input=df11fc0ea107 vt=0ef28c94e4c7 graphics=8a631615821d history=37f5de85229a ansi=ef6cd391b992 ansi256=b5de86d12a9f html=586083cbebef
269-22/099 924e3f255fb856ff7b7dc8ed269+22/099 input=c4176d57bf31 vt=1c723153a857 graphics=481ee10342ab history=a250b6417499 ansi=aa77d5716663 ansi256=d57198ace643 html=fdddf431d85d
270-22/119 53fcd1df652d602fe412c5a0270+22/119 input=1081c942b525 vt=b1b795f197d6 graphics=02b28bf3aa32 history=1bdee1ef0937 ansi=b6ea7c081f1c ansi256=ede92df0ea04 html=0de5a23e4010
271-22/139 7414a5f8fdbd506ab15f698d271+22/139 input=cd85644bd3fa vt=be34e6a836e9 graphics=432fedf48712 history=6f54299845b5 ansi=51f3c1f48e96 ansi256=53a36e5a7b0c html=f37ec24a96f9
272-22/159 bc2dd2281c12435224135073272+22/159 input=94e080045d0a vt=a63997ef6095 graphics=bae0c9f75b53 history=f4e3d587bc1d ansi=f6581e7652a1 ansi256=356dc4385c7b html=2734dcee119e
273-22/179 dfeef83df0e865e875132be1273+22/179 input=67502dd99a94 vt=0d12c6645323 graphics=e1fa932c581d history=48618f2eb924 ansi=e62c948f7b61 ansi256=2081f7d8fd89 html=ab1ed984b294
274-22/199 9fe1387f10258c696fd9e783274+22/199 input=1a875e7489aa vt=30f0de781b81 graphics=79bbcc4a697b history=d74cb6820539 ansi=aafe502a3368 ansi256=803867175a8a html=fc1e839f63b6
275-22/219 3009560abe632e04450f7f41275+22/219 input=97cd8f5e7b40 vt=329131c2c98c graphics=5d057491e906 history=761f4a4c1a0a ansi=8ce94a66a529 ansi256=30c70089306d html=321dae654bca
276-22/239 fe8d129db62a73ae9b9650bf276+22/239 input=74ac88bf42f0 vt=6302e4338e3e graphics=8248f4385dc8 history=057a1e67dc5c ansi=26f0bf26e9d6 ansi256=b8b0feffbd10 html=7ba1561dda31
277-23/019 20cb94d03695ad09763e03d2277+23/019 input=1ac834dd66ad vt=0703283520c4 graphics=9258c91bf1d0 history=d5e92dfbe7ad ansi=59ff2eeabc7d ansi256=4d98e3b459c4 html=1f588a40164e
278-23/039 6c18ee020345a7699fd75494278+23/039 input=52c7c552e18a vt=c7c6f6a3b87e graphics=762d16b098e3 history=4b446bb67c28 ansi=4f977bf9ba80 ansi256=62ce599a19a8 html=20cbeb3461b3
279-23/059 f85c5ecebab82f1126f3c964279+23/059 input=c728326cd041 vt=53fdafdd6168 graphics=15ef31cb4efb history=dfd246f6a230 ansi=259d4cb646a3 ansi256=afd261fca4fe html=b759e05e7e42
280-23/079 2fbeda367e9d56072d5b0edc280+23/079 input=72846e647366 vt=64fac99bac94 graphics=212e4c08e2cd history=bea125990222 ansi=1080f1358b3f ansi256=cd3bfdd4c44b html=2e124eb47c51
281-23/099 307896059fd55149f9d7c7e3281+23/099 input=6b584e536c32 vt=76fa20f1b2f7 graphics=279ae557dad6 history=1e92e99bf77b ansi=b3e9a6850cc5 ansi256=d1a86aac3718 html=9ad39e087f83
282-23/119 73bafc1697a5e247b2d3c75f282+23/119 input=d1256672f808 vt=5fe9b2f6c14c graphics=52845616bc40 history=318e8e7794f5 ansi=4ea8c0bfe1e2 ansi256=0fb5fd863f3e html=e668e50f26a0
283-23/139 214cbbca9ce4b1d0c98ea569283+23/139 input=55d0a8e00404 vt=3f27f2fbead5 graphics=991903976c4a history=8423992a5268 ansi=e9e74ee182ab ansi256=ab9911e6e52a html=7cba44ebb246
284-23/159 82259d749685c0f294be858f284+23/159 input=3a92a89887d8 vt=405b4ec5829d graphics=a94c75564483 history=fcb99eb85aa8 ansi=a64c8cfbcf82 ansi256=10cbc31927b9 html=0085b8454be1
285-23/179 8d7b14f89c5f5d3113fbb3d2285+23/179 input=0d5a633cd93a vt=219797ad4bde graphics=cdbd6f5d52b2 history=002c612acebb ansi=c91018b65a7d ansi256=cdd0b78340e3 html=1228a2356628
286-23/199 ddee2d89e0897e90f9a6df78286+23/199 input=c9c456495830 vt=fc7556378cef graphics=3bda366a4653 history=6a4964108626 ansi=6c0ae68c7db9 ansi256=a451eedd0781 html=4ad42d85bf40
287-23/219 65e4440830b9f98e48fe3a11287+23/219 input=8c41bfb460a3 vt=144903b07554 graphics=bb4b123e09d3 history=9b0ea55ebf1e ansi=2dc10f02a8d5 ansi256=17ab91693041 html=607a11cbb2ba
288-23/239 e8ca9cf0699b2c6333e0cb3e288+23/239 input=ccd5bae9d0d4 vt=3ee3e4bcf2c9 graphics=fdb9c488c44f history=433238a91160 ansi=b8a97608d2ef ansi256=52ef6c545a86 html=d1cbad075fc6
289-24/019 b7fdbacf57cb0af4d47225ba289+24/019 input=148102104127 vt=e22fcc59d5b8 graphics=f8979b697ae6 history=e3b0c44298fc ansi=40b1b6544cc6 ansi256=636b355a35cf html=2ef429ced7eb
290-24/039 a6c7f740d5d06f67495f9e33290+24/039 input=018bead9b7ae vt=205c10c84d59 graphics=3342f04c7491 history=e3b0c44298fc ansi=ef8059fcac20 ansi256=1f000c7cc8c5 html=5c88341ab5a7
291-24/059 43a01382b5ac0c1ae9bed9cc291+24/059 input=319607f49e0a vt=9cfdb3b9dd63 graphics=2b7e7b47aa81 history=e3b0c44298fc ansi=349f9af1db55 ansi256=8ea789af1a5c html=580f5c77e3e0
292-24/079 b1920c5092ae3660a5d16b80292+24/079 input=e6926c76740e vt=517f29d0eba1 graphics=edc4d4e288c8 history=e3b0c44298fc ansi=5210df2c3aeb ansi256=42d8552bc074 html=e9ac7656e9d3
293-24/099 6c5e0cce477b33f47b106ea3293+24/099 input=c18757c3b799 vt=b3a83e738a66 graphics=c60ca86be87a history=e3b0c44298fc ansi=66b4681f9721 ansi256=a2b0bced4166 html=a9d1c68677ca
294-24/119 6d6f085ab19ecfad1a4a2120294+24/119 input=9861958c685f vt=b6e7b01496c9 graphics=c709a324064f history=e3b0c44298fc ansi=e3ce39e0ae12 ansi256=8674e90c5215 html=6d9550434d86
295-24/139 9547bae694f87fb2c2b3d311295+24/139 input=05cdfc1f5efe vt=038e0c505a83 graphics=193805159acf history=e3b0c44298fc ansi=3bb5071299e4 ansi256=822567388615 html=92f98a360d36
296-24/159 4acc87c8a3480147416549a0296+24/159 input=8e607996da30 vt=106b19e6ec5a graphics=8d6375572fa1 history=e3b0c44298fc ansi=d6f1c798ec9b ansi256=bba4bb627baf html=24ead4eae2fd
297-24/179 e0f7f82de3ea5bbb6bc4c259297+24/179 input=dfe92c6f2bad vt=a9348116c0bd graphics=cc914d760012 history=e3b0c44298fc ansi=1789b413341e ansi256=40f767a2dc82 html=58c9042c8c54
298-24/199 accc2199dff19d266f855064298+24/199 input=4c2553c2517c vt=02e131e2d775 graphics=7bb2aa5d8d6e history=e3b0c44298fc ansi=48beec3c3118 ansi256=d6123686c1d3 html=80edff930a81
299-24/219 a763e81bff4e145b46922cf3299+24/219 input=11342eff7098 vt=8a82550741ad graphics=6d72ab39e211 history=e3b0c44298fc ansi=5c8067ce0751 ansi256=c61a4dc165c3 html=1d6c3461c933
300-24/239 5299c46a14f4fa125c9b8611300+24/239 input=7701b418b2c4 vt=29f384a3aac7 graphics=483f93084782 history=e3b0c44298fc ansi=76141e442411 ansi256=60b08d80a715 html=5e79b9d39bf1
301-25/019 eb73f8f3bb46422a6a12fc8f301+25/019 input=52d18b6088cd vt=fca038dd5083 graphics=9258c91bf1d0 history=028563431d2c ansi=de864fbef6ad ansi256=da875ca937d7 html=988825f1a0f7
302-25/039 823c96945f71196e67f10f65302+25/039 input=9371bf89fcd5 vt=8254bb5172ef graphics=ec94ae6cc7b9 history=c21a1e2aff02 ansi=e6312cb66040 ansi256=2de9bb4807d5 html=d38a6e4486f6
303-25/059 c04f006b9f600ecd075cec6a303+25/059 input=648f90254a8c vt=7bf7a9fe2551 graphics=f3e88db7524a history=2a7d136dc209 ansi=11532c02d511 ansi256=ce3e2ce9182e html=d93a806b0199
304-25/079 a21fe1e939c9fa2ddbc2d385304+25/079 input=ac8a64fd0669 vt=9055770e92e0 graphics=03c96da25a3b history=695aba930edc ansi=909609df56dc ansi256=c698724afe00 html=161836d0b719
305-25/099 c20fca1d42014ae0701d6d0b305+25/099 input=b9cf01acdb26 vt=8dd2058f433e graphics=21a529189863 history=5238bbd06b82 ansi=b5d4088e160c ansi256=0ff96150e2be html=1940b52d8463
306-25/119 3b6b3af160572b8ebc24277f306+25/119 input=410378a33ad3 vt=dace7518854d graphics=671c04cdbb2e history=ba8ffc54516d ansi=9daa743e922f ansi256=0f6bdecf771b html=abca3838f07d
307-25/139 e6151bf8cfffc442059ea129307+25/139 input=d5c58840cccb vt=a863354d2e79 graphics=774c3af4a9d7 history=fc832c985019 ansi=fd8a33c8643f ansi256=248acfdd5b79 html=2d2a6142c2a0
308-25/159 5209600fc448f453bd687cb2308+25/159 input=c779a92ffff8 vt=59722e5604cc graphics=90138c047ccc history=784062fd993e ansi=4fd68de4eb47 ansi256=47fac1db6a5e html=c9fa450a5ccf
309-25/179 043175bc5eea52c09fb8f884309+25/179 input=0f10e10ba19e vt=35008d097bad graphics=893057b33dd8 history=16953fbaeb54 ansi=3b27b5e8053d ansi256=7da8c6e6e855 html=78d28e5b20c8
310-25/199 4b7c1cd9781ec41bf596b764310+25/199 input=0ca98a998041 vt=8efd480ed24b graphics=63413593bec4 history=47776a85fe59 ansi=7d7d4c66a6e8 ansi256=5bdb0d8d7bbf html=0ddc17f9e7e4
311-25/219 ad62688c776574ab5c442de7311+25/219 input=de28db3b700a vt=17daa62c7cfb graphics=dd49376c4da5 history=15a33d7773c3 ansi=ae80596f4399 ansi256=82c08aa54c2c html=7a6d084b97d8
312-25/239 22e025d483651540c55002c6312+25/239 input=7376fea910e5 vt=fbb1d592f8d4 graphics=91fce35d7281 history=9386c1fadc98 ansi=6d4a3a73dc23 ansi256=868fb03a774e html=8c0629d2bc33
313-26/019 122c0cce3cc0ece13ce6f89a313+26/019 input=fda9cdcb5b52 vt=facd51ef20c8 graphics=382c68b55f88 history=77c1e92b28ce ansi=2ca00c5ec060 ansi256=d468b0312f32 html=99c7671e334c
314-26/039 0999ef9b5da72bc75cef9d49314+26/039 input=45dde463af51 vt=6351e7ebe54f graphics=2b4e93560776 history=6d6bea4b9262 ansi=27f8e6f34ff1 ansi256=5497e744c3f1 html=d35ad612683b
315-26/059 2efdbf6da4b726f10f2878d1315+26/059 input=7da19667b980 vt=d0db0647cfe6 graphics=5489354feff2 history=2a69dea37d81 ansi=a198b376a5f7 ansi256=b9ea808c723b html=f0d8237c3bca
316-26/079 f899906f635ddb86d5c73984316+26/079 input=32a6d6a2b1bc vt=cf96bfc4e6a1 graphics=3f478b3003e5 history=9127b57731bd ansi=47fe1fddd752 ansi256=8c4757767979 html=140d6ef6fcae
317-26/099 46367bf24897cad56dd5235c317+26/099 input=6f6ab6c33f6e vt=8d0bd32b9860 graphics=41c51ddaef04 history=e1fc29444d46 ansi=ad7570e6e1a9 ansi256=54ae825a2d51 html=b5202ae161ea
318-26/119 a97b04bc18332773595951da318+26/119 input=7268ff0f428b vt=3570eaaa8987 graphics=1536a47eea05 history=d4ca4f97cc2d ansi=6f955f7061fa ansi256=9b376649c4a3 html=4af6ca84ff47
319-26/139 c5ae15a2b57146ef155e27b9319+26/139 input=a035d95e4133 vt=31fd63dcc343 graphics=56623268bf21 history=9e9e09147d59 ansi=367469570f8c ansi256=c1d131bf9d73 html=8ba9423aab63
320-26/159 51ab1eaae8be298680367404320+26/159 input=13dac00ab83f vt=f3886857efe2 graphics=9c93b507d033 history=1d61914d4451 ansi=a70745216d22 ansi256=38f3aa51849a html=d7d9e3d8e315
321-26/179 e35bdd23c19b6295280181ed321+26/179 input=b74e39ac0058 vt=cdd2058ecb63 graphics=24b3d853ce9c history=40a77b124d6c ansi=2f8eeb70c459 ansi256=292c6f4b1128 html=ae88fcc454f7
322-26/199 5f21c27026ba98b0a9d5d51c322+26/199 input=644a9acc3e7c vt=4d3b7e94ad9d graphics=105f7d3ad244 history=bd347f14b6ed ansi=db8bc20b0152 ansi256=db77852447fc html=e9b1ffb17748
323-26/219 2fcb984adf0b347e0da88d33323+26/219 input=3a73386e101b vt=32bafcc85079 graphics=29eb959b5720 history=69a44f4a9e2a ansi=433ef0c96908 ansi256=ffc502920bda html=329de537b64b
324-26/239 200f40ed44f86ce04857c1ef324+26/239 input=41caba3e4176 vt=72cdbafbedfc graphics=f103e171dc0a history=e01e78beb0e4 ansi=42e5a332cf10 ansi256=ffc9fdbf7eaf html=506fbd125bbb
325-27/019 ee2c010c41b9f0e5f70ce2b3325+27/019 input=a0ab158021a4 vt=4c016f9ab6b8 graphics=869d15133c58 history=b02d2b5c146d ansi=a66af5fe25e3 ansi256=028c81af44b0 html=fc80a7830ed5
326-27/039 91ab08fb270466abbfb06c54326+27/039 input=619d48ca4875 vt=24a873ab19d8 graphics=e591a2412917 history=93d77aa8b991 ansi=9627caaffa74 ansi256=7f76f10a45e8 html=93e3f0ec2811
327-27/059 2e73fe488420a5de3866e7e3327+27/059 input=37323836c954 vt=a7361b81ab9d graphics=27fc3572e7b4 history=30619de4a0ee ansi=786e44106197 ansi256=bf3797a8c835 html=9c5c832eb751
328-27/079 a72a80db0e8ee9bffb891b38328+27/079 input=9a19b64b0196 vt=f1baaa7f0a85 graphics=ffb49c684293 history=37e041c6b820 ansi=f7f24c82de96 ansi256=a5f5110890de html=15c69493adc0
329-27/099 917cde1321cfce583a63d9f2329+27/099 input=d12989c27d01 vt=a8fc3484ba05 graphics=c8e28e457332 history=a8279232604b ansi=98ffda5977b0 ansi256=534a060f046f html=e39368befb4f
330-27/119 b8056ec6e08df1e2f7033b6a330+27/119 input=0ac9080d8928 vt=b83980a4008a graphics=da849ea45a90 history=5c3d8be7a9e4 ansi=2b2e932c973a ansi256=21b8da618178 html=1c8956fa86b1
331-27/139 22214c1a34de027d97f18ad9331+27/139 input=282ef624dfad vt=d6b004fd262d graphics=12a2e8a9f60d history=1329220e670f ansi=2298fb0d8a5b ansi256=11e812bae71f html=92e76791613c
332-27/159 18debaf4cd5dfd2bb665bf34332+27/159 input=a01c716c963c vt=13e121a5ed05 graphics=e6459b86b3cb history=3eb84b471759 ansi=f690218fe3b4 ansi256=fc21b25f6924 html=2621c438c156
333-27/179 b8c41633f2ea27468edc411a333+27/179 input=20f00a694447 vt=94321f06be09 graphics=a3c4c9c6f33f history=42d4520330a0 ansi=a2a46388663f ansi256=a376fcbb8164 html=655351f8ba42
334-27/199 85bc90436e42fca40bd64d3c334+27/199 input=fdb67ef93b9d vt=1838510afa9c graphics=d29b34fbd961 history=df63294e32fc ansi=827143c01f7e ansi256=b85859dcbdb9 html=035cf7541b52
335-27/219 f0dbe3da68c8dd144c3dd9b7335+27/219 input=8ddfbab95f21 vt=e45174a8db12 graphics=c97d30325b64 history=62fa448733e2 ansi=32121881889d ansi256=4b64757e726c html=bc0256e425bd
336-27/239 214002b3d936e2fe396aae01336+27/239 input=753e7bf06dbc vt=60f1105433d5 graphics=efbf1f464724 history=4a90c407f9c4 ansi=c4071852a228 ansi256=1f57fb29fec1 html=f02e632104b0
337-28/019 3ee1c2f031af3ad67ae50ebc337+28/019 input=391f94dcf6a1 vt=39ec4af818c0 graphics=9258c91bf1d0 history=e3b0c44298fc ansi=ed7d4a6a2cf5 ansi256=f02d1647a112 html=0c6fd0634bab
338-28/039 07508b3af21ec20fadeefe55338+28/039 input=a2dc4b392a48 vt=b8e0c66df113 graphics=83d520edbb4f history=e3b0c44298fc ansi=5c501391013a ansi256=048ac49fbd32 html=c6cb7696f2fe
339-28/059 dfa63544d3d6a817a9212067339+28/059 input=9512e505bd51 vt=3fd50ae5cb19 graphics=2a04a7e76271 history=e3b0c44298fc ansi=38d1d62d4cdc ansi256=7341cbe0d85b html=fa39f477d565
340-28/079 237f6a260f672d353323e622340+28/079 input=b4f33aa964fd vt=e8a914500faa graphics=b84eb0ef5e85 history=e3b0c44298fc ansi=5d58e0f3cc04 ansi256=0bef41c71264 html=c9b7d0a74d28
341-28/099 3fa387d797ef0467f5e6e7e3341+28/099 input=42c86901a419 vt=53cfab76eaf2 graphics=e919013fbcfe history=e3b0c44298fc ansi=d60a7106690d ansi256=674909bf361d html=9168b1416cb6
342-28/119 e25b9e12f6c5b3b03510cc14342+28/119 input=e00da70055da vt=7de1f675883b graphics=f2ef9f6ac5a5 history=e3b0c44298fc ansi=2aabcf8d8eee ansi256=168b25bf2b19 html=e22b7e487e36
343-28/139 1740ba1423fde72696b1cb5f343+28/139 input=d750a1ac07d4 vt=b315c0f1df33 graphics=ab0ed3a804ae history=e3b0c44298fc ansi=e9d617aa4089 ansi256=fae71b6133c8 html=01972989965e
344-28/159 087e829214051615d334f3ef344+28/159 input=3fc7f46eabe8 vt=ccffd168fd63 graphics=ec03ac4ca0cd history=e3b0c44298fc ansi=11a6c758321d ansi256=e80ed90c3bcb html=f4bcab9117e6
345-28/179 86a425ae6b5b0e26b2d91ade345+28/179 input=1d4acd9c4af7 vt=8bf36c9b23ee graphics=1911cb9145c5 history=e3b0c44298fc ansi=56763f90b125 ansi256=d9a87c01b2b1 html=d002b29e05f2
346-28/199 38502b27dac76ac25e7d8b3b346+28/199 input=1856f88796c2 vt=0abd510a59d6 graphics=057f85e08328 history=e3b0c44298fc ansi=b0d6f894f6da ansi256=aeec9cff2fcf html=57f2df151504
347-28/219 407ae66e6aa5fd9602e5e5ce347+28/219 input=cd27a5fd4004 vt=4ac4f7028196 graphics=a5316d8dcd5e history=e3b0c44298fc ansi=aab02f46cf70 ansi256=5b2060872b3f html=c2469613e79e
348-28/239 b2630d52745798f40a5a034d348+28/239 input=1670f4358e8c vt=89328e3b3947 graphics=d91c8b353650 history=e3b0c44298fc ansi=c75943df0217 ansi256=919688b315c1 html=d1989ca8a68c
349-29/019 72e981fc506bfdd3bbf15c37349+29/019 input=d2b5871bb414 vt=c052ae09b304 graphics=9258c91bf1d0 history=d3fd1a0b8244 ansi=91c870d1933c ansi256=f4e29987bead html=b4d07df3d6cd
350-29/039 8c46bcf213fe0e9cf159a7d2350+29/039 input=5b0a2705ef4d vt=0d059bd5f42f graphics=8142d34d582c history=92f9707352a1 ansi=b43e08309a86 ansi256=19b9af5d6ae0 html=fdc190cf1253
351-29/059 213c8dd3d5bcda3abb11ab05351+29/059 input=47ada4f1019c vt=b40f6e177d1d graphics=1e0eb8920f76 history=6db573d69703 ansi=41ccfb4ac2df ansi256=649bc6b5da2f html=1e5bf7f9470c
352-29/079 5c42ca0bf2bdde3f4e8beb0e352+29/079 input=8bc9e83b5a81 vt=374c8594de2c graphics=0532805773dc history=46255be21ecb ansi=765157fbeff5 ansi256=b88f874e8c6b html=072a60554e2e
353-29/099 9da53eccca7406686de96ec0353+29/099 input=9f1e5c464abd vt=aa59b0b22cf3 graphics=d2d3cdc33260 history=37760bb8481b ansi=989b753bd4f7 ansi256=7050ab6e10f1 html=8b9a85f51a19
354-29/119 c91f989577473d295e74d700354+29/119 input=cfc6143e2e7b vt=1acd379f3bed graphics=c7f90dde3e58 history=067212979178 ansi=b0093eb9ed2a ansi256=0219a9bbbc74 html=91eb9810990e
355-29/139 6d5ff6bc1b1b73cae023806b355+29/139 input=6953c4cb1ff3 vt=da2df4505df2 graphics=d87e27f1fedd history=bbbd1009cb0a ansi=45612d00f8ae ansi256=aa563cf04415 html=1a16506e94ef
356-29/159 a1e1bfef4df06dc65e727a5e356+29/159 input=7625b8495e7f vt=865ffd108fda graphics=b39ba83c432b history=3556ac8bf0d7 ansi=df732e1bf1d2 ansi256=ec385b448b4f html=a2fecf7db3fe
357-29/179 afb819e69c5c53d51d49d446357+29/179 input=b321a53fe360 vt=69d2a8985995 graphics=58400326653e history=8f690969e6f2 ansi=a64950b43d96 ansi256=d7489c15a4fc html=2ad62006a5e0
358-29/199 78df663b24d8507a469a7959358+29/199 input=37191c6fa49b vt=51dd26cf6374 graphics=c98569c74a00 history=a2bf34248497 ansi=f956527071d1 ansi256=4a45079fe8e9 html=be2bb9129a02
359-29/219 e40592fde61b5e14bf73242a359+29/219 input=55e0459a5d06 vt=570ab6ceac22 graphics=5ffd6c200c89 history=52e3c5d61685 ansi=17dc0c38ee41 ansi256=5ddb6f47a5fd html=fc6cb77549f6
360-29/239 b6629ebed5f6c79374cf4cb8360+29/239 input=3423aac00df5 vt=1c71bdbec8c6 graphics=66cfc819e87f history=0d94a263950c ansi=37c75f4e6ee9 ansi256=9cbe40931eff html=249158fb98cd
361-30/019 ea74787caee42ed3665575ed361+30/019 input=81b751d4ee69 vt=cd8eb7cdf707 graphics=c8d8b5e0d84c history=2c3d149755a5 ansi=46df2034c3bb ansi256=5c4635e74a7b html=ba6e227155d4
362-30/039 91b5e5afa5d3bb06b087f6ad362+30/039 input=f2ea78ebc633 vt=32f6e4b794b5 graphics=0c4a8732135c history=d2fd3d71ad52 ansi=5d06683bca49 ansi256=2e3c3f8e2573 html=08fef3cd9bf8
363-30/059 ab536abe78f0cf27cdf94a75363+30/059 input=b5b88be76b35 vt=a89c35759631 graphics=0a16a95018e3 history=dd5821495eb2 ansi=8212058f2c16 ansi256=bf999a03348f html=a120f8550939
364-30/079 cb0e90a99459de9ed8493a87364+30/079 input=aab80cdb1a9d vt=bad39e3cd313 graphics=fbde544e97db history=a6b95b04c20e ansi=bb5e412c315f ansi256=d3806cd75402 html=f3b857fe9281
365-30/099 24cda2b6890297d9254603d1365+30/099 input=fecff317770d vt=dcfed4e41776 graphics=62e6fadbeb33 history=f0143cbc9235 ansi=372309dc5b18 ansi256=a1a2575fa6fc html=10213ad6969e
366-30/119 dc93cdf4c2014d22ac4d1ef2366+30/119 input=f36a0921e2c1 vt=c1c87f7aa7d5 graphics=0e5650a6b594 history=2539236c8d07 ansi=b44c19672ced ansi256=e63496a082c5 html=40fe33da0bc3
367-30/139 66e5417af5336b68e70cfa14367+30/139 input=1235b90e027c vt=92378b77cee0 graphics=6570bcfcc284 history=29f785a303ff ansi=f95d045ca021 ansi256=96ba741a02df html=a02c2c05f24d
368-30/159 c10f3ab9c58aa3f43caa4f94368+30/159 input=0a9c4944432e vt=c1c4f164e2ed graphics=9655c95832a3 history=5cab22d70e85 ansi=4d8b73aa1781 ansi256=d017ea26c731 html=9d428fd38757
369-30/179 a7d6695e7add8ed6e7912161369+30/179 input=8188ef7c5aea vt=9df594a81c83 graphics=6135d5ea25a8 history=2171fb6763dc ansi=746fdb74c702 ansi256=4403fc8df293 html=f17ee03f7c5b
370-30/199 f1fe2d3081c9ccfc7413e3a9370+30/199 input=4abad5b6d552 vt=e0ffd787a8fa graphics=c3ff71dd99e8 history=8c073ea7f31b ansi=877f98e30188 ansi256=8a662a41ab7b html=9f046facb643
371-30/219 5c1dad4fffc15226a5eebe51371+30/219 input=c466091ffc3e vt=6fef0ac7c1b5 graphics=92faa40c0c50 history=de0ca81512fe ansi=cf605527be7f ansi256=d982cf06fa77 html=728ea5986192
372-30/239 966ff4c469452f7951326c5e372+30/239 input=4145ebca2134 vt=43dee83cd99c graphics=a10996d846e9 history=9127a917775a ansi=48031030271c ansi256=644c27c658cc html=520641374e9c
373-31/019 869af9273a068555a7c65e06373+31/019 input=4ffdd107e130 vt=a8f488f70e96 graphics=54a47f32d294 history=1363d4610810 ansi=d12a1938e477 ansi256=b3d7ac12ba37 html=709869c68aa7
374-31/039 af9002bdf228a2e1f034df74374+31/039 input=580dc6809479 vt=26d09ae8088c graphics=932b610185a6 history=546bb0ec07c3 ansi=3d73d7b4ece4 ansi256=c9f2585ef571 html=c1b184bd2031
375-31/059 375fd592eea7fdb3ce4a7563375+31/059 input=d55047314620 vt=ba8944f37704 graphics=93f9c09cc57f history=13263e91f3a0 ansi=b7e22aa137a1 ansi256=ac0dee7439a1 html=6c0652e529c3
376-31/079 8d6f8e9a242c0da7a8707d06376+31/079 input=481041bbdeb3 vt=7e2b3392c536 graphics=96a7f4c0e9cc history=b4e2710a711f ansi=5bd2e666b439 ansi256=f75b592537b4 html=a4af462fedcc
377-31/099 f4e05fd0482cb95b1141b933377+31/099 input=a0faf263fb01 vt=b8a49978e022 graphics=8102f1a4335e history=2fe4211ff34a ansi=be22be7e7f00 ansi256=879a70e29f04 html=fdf426a8f598
378-31/119 0499dd21ead9843ec3668589378+31/119 input=187877e7efa8 vt=73e5614e80b2 graphics=9569fd17b61e history=241eea6af7a7 ansi=8bc768ccea64 ansi256=a5c49983195b html=cc65f0a09f0b
379-31/139 8fab9f1300b2d8c6757a9587379+31/139 input=de7b035ba613 vt=9dd8609cafec graphics=d564f22f470b history=0184633328b3 ansi=4bdf20abbc23 ansi256=330f23d0aefb html=42ed22d9a936
380-31/159 e5ea9bef6d0ff097b0b0f00f380+31/159 input=b6fd5e5706dc vt=797000293a6b graphics=7a52d325bebe history=7610ffcf2c68 ansi=b3fd23a46a82 ansi256=eccb38052f3f html=0038d1a5f1a9
381-31/179 2d21760a2b468c1f8e101b86381+31/179 input=8c6baa09d601 vt=14bcb2ac1ccb graphics=c47105a03d8f history=bd6755a03aeb ansi=f5bad7cc857f ansi256=f4e17410acaa html=895199ed0c72
382-31/199 1c76b93d064c496485782148382+31/199 input=e93f7c591ad3 vt=6d96a17aba6f graphics=2f720cb29179 history=3a9736691489 ansi=460307957329 ansi256=80e672ca3ac0 html=b6718ba45e5e
383-31/219 8a23244f3e0b25b774aaabbb383+31/219 input=79773cf0de2d vt=186bf619a34a graphics=f49eef257c76 history=5aa2cfa1b249 ansi=ae7c27b07155 ansi256=7c18b74d2046 html=0fb7696ea8eb
384-31/239 6b47e6b3998cf340d47f2dc9384+31/239 input=6c9d844e01b7 vt=54d6672972da graphics=121fb62a4ac9 history=973c3872c5f5 ansi=0d6dc977f68d ansi256=8dfe6cc64918 html=8bd17b2d00fa
385-32/019 ed11b0c6e02dfce865d49934385+32/019 input=f1b9f49825d1 vt=b896febefb87 graphics=5b44277a67f0 history=e3b0c44298fc ansi=a59d647eab6b ansi256=dac7099fe2ea html=834f953e7816
386-32/039 bd3bbe698e10adf1f5fbc490386+32/039 input=2a33a289496a vt=b5916d7070fa graphics=26d5bc17baae history=e3b0c44298fc ansi=7f524a65348d ansi256=0db81005952b html=2dbbc99315ad
387-32/059 fb530e83cb69ec498ccd32a7387+32/059 input=c744aeba9d35 vt=1f7ab0ed0a85 graphics=19bea48d4bbe history=e3b0c44298fc ansi=48f20dcecafe ansi256=cba05808b822 html=cd106657a417
388-32/079 f54210cbb277563ac36c611d388+32/079 input=a291715ca604 vt=02dae80575f6 graphics=cc3ccd321b8f history=e3b0c44298fc ansi=e60a2f443845 ansi256=fe695b1b74da html=5e5dce1dbcfb
389-32/099 9f2557fef0b33c2da3b1e22b389+32/099 input=0185338fbcae vt=8fc5a3e651b4 graphics=2f6b60f4c1bd history=e3b0c44298fc ansi=6bbbc41196a6 ansi256=d1c3be6963f5 html=38fbc5c0e198
390-32/119 4b02e8f56434d83e8f5234f6390+32/119 input=5bdba58e56ef vt=fae5a689ad92 graphics=ad43c49b7a64 history=e3b0c44298fc ansi=0ce313ad92c0 ansi256=c13d348e44ee html=691cf37c35d0
391-32/139 39feab897a9120d585c20a8e391+32/139 input=c1db2991e5c9 vt=54093b9b2429 graphics=3df6b10ab88c history=e3b0c44298fc ansi=e31e25be2279 ansi256=f64244a7e151 html=691a9628b531
392-32/159 d0953ad716ea690de47dfc3d392+32/159 input=591789c42d4b vt=c24909ea2afe graphics=c236f799ecaa history=e3b0c44298fc ansi=022f0da69021 ansi256=239a7a465997 html=8e5993493cfc
393-32/179 f6a7b77c5991d37449e779b1393+32/179 input=65675fdd79cc vt=19f4b67d3b4e graphics=261327b79d5c history=e3b0c44298fc ansi=a3b2504f775a ansi256=afb363d453b9 html=201666f5a199
394-32/199 2c188342e677e30c8ffe7f9e394+32/199 input=05390be08cb1 vt=4bc9f1107e39 graphics=fa6550382379 history=e3b0c44298fc ansi=89d28c0df975 ansi256=805ad4ff7ce5 html=ebc32b3a93e8
395-32/219 7fc717e4fbfd57748ab342e3395+32/219 input=80d7f0067852 vt=d430bffec709 graphics=5c1d55bc5c72 history=e3b0c44298fc ansi=06fda943d841 ansi256=a76bc4ca9ca4 html=088e8f8b6c28
396-32/239 506a3d22b3e2ff760873e0fb396+32/239 input=9971f0ae2fa1 vt=9ab36840c246 graphics=aa7fa2241277 history=e3b0c44298fc ansi=1c7e054f03bd ansi256=f377130452c0 html=96b525a29e6c
397-33/019 75e34d5589c8f836a06d090e397+33/019 input=4d8ec4a4118a vt=223f264f2447 graphics=88d9ff5277da history=711a38708632 ansi=080247111071 ansi256=db0ad0bd8b9a html=8578a4d939fd
398-33/039 372c230667e378656b2af4ff398+33/039 input=72bd61b19dd6 vt=525fb700abae graphics=cdb95740eded history=0d7c8ec46243 ansi=292ed59cca0f ansi256=5370dc6a7441 html=2cb3a89f23a4
399-33/059 938b86084dbb06afa4454b27399+33/059 input=230c9af2f983 vt=e49b983f0af7 graphics=a9ef4a02744c history=b77790113127 ansi=cb2676a2038e ansi256=adc4188bb526 html=8b3de2c7c4b8
400-33/079 7fa7265281d43e73b797d780400+33/079 input=4df91df6e37c vt=fb750cb35392 graphics=818dbc92bea3 history=23a3886975c8 ansi=13f3aa9761bb ansi256=064a59ef4fc6 html=73c2a40af02c
401-33/099 ac83290b711b8dec3003df47401+33/099 input=678d23120ba3 vt=6d6b38fb0388 graphics=92ab0d9966af history=2ca97bd48c2f ansi=d0fbb5b13d15 ansi256=c0d1412e905a html=1491accb4ed3
402-33/119 021ac2bab909abdd6e5c77b5402+33/119 input=bcc5b1e12cec vt=3f46ce9c8abf graphics=ec245d1603aa history=5032daa96a10 ansi=83456a35b8e7 ansi256=7860a7f16450 html=ff85921dc9bd
403-33/139 ed69b8d8881a85100d32c4cd403+33/139 input=3adcc6ae924e vt=b9fde658c5a9 graphics=5ad851d25e4d history=3a916388dafb ansi=f3cf449bbd60 ansi256=b72ae24101a9 html=61ae977e257d
404-33/159 c1566ad91ec422c65923fe34404+33/159 input=fb7643e0bce4 vt=74c506f158c0 graphics=5b509853d2db history=877c1724a1fb ansi=fa29a37cf87f ansi256=fcac20dc9549 html=2548f41db282
405-33/179 9275113b9df0b001112ad573405+33/179 input=caa52db0cbdf vt=e75162de1b89 graphics=d949a79b005e history=bef9891a91f3 ansi=1b75efb5c608 ansi256=fc91fc6f771a html=82ffdfbb26d7
406-33/199 a269fac1fd59ac746cdcc3ed406+33/199 input=c2671cae6a9f vt=e7b36b067938 graphics=d6eb2ebcb29b history=7334f6641140 ansi=0b8aa22b4190 ansi256=49b67dd6fae1 html=a4d1eca5d7e7
407-33/219 8efc32f7b432b011f6862afb407+33/219 input=e7cea0a5df37 vt=1de3013b4d64 graphics=cf342952544e history=f0e0478fb828 ansi=23b4346842b6 ansi256=1866c47845b6 html=63bc52ed79bb
408-33/239 360719a27cebdd0863b2e775408+33/239 input=5e15a796e7a7 vt=9665e614c843 graphics=94587b3237d4 history=6be392d9a77c ansi=f69f3eaf9883 ansi256=4275a0f5d1ea html=fc5fc2a96c78
409-34/019 93dcae1fc2bfd6779aff1aff409+34/019 input=178da8bbf142 vt=205910068395 graphics=dbfcd55d0b33 history=7502eeba6bb8 ansi=8163280cad67 ansi256=159b42c6fac6 html=953e473e01fc
410-34/039 e4c849c2eb75db26ab3e4a69410+34/039 input=a1bc6765e27f vt=48042beef7b7 graphics=29f7f17a132f history=6ec8d7f5ecca ansi=245569305424 ansi256=13017bde2cac html=f75731ef87a0
411-34/059 f44f95efd2e73205143c656c411+34/059 input=949398406918 vt=90cc3b7424e8 graphics=8c7bfaa71c9d history=8638567d108a ansi=e21a53a5acc1 ansi256=d4d06f3e4053 html=8f242eb9352e
412-34/079 500ac8d59cbff22ad8cedf95412+34/079 input=9d2e927f6a2a vt=3d041543a44b graphics=8cffef3c56ba history=79b1b371a8e3 ansi=082ee3283735 ansi256=8ed8beda9444 html=f229a8e62de4
413-34/099 8cde09d8fb843f0771e27c68413+34/099 input=28020b63bbd6 vt=32c06be61be0 graphics=20301a3655ce history=6679d91bbfd4 ansi=42bd595e6e1e ansi256=afade28b969a html=d77c51a7fc40
414-34/119 8888149eafa436929ba9002f414+34/119 input=daf68c036c3c vt=af9c947f7422 graphics=5441da3a6af7 history=adbdbeea589e ansi=93a79bdb653b ansi256=82786c1b4fa3 html=0983d1771e07
415-34/139 9c9180251a5d41fb6bb84e0e415+34/139 input=6d25662acf3a vt=5cdb4756e6b8 graphics=ae0700fd7a09 history=acd95dfdc46d ansi=0b761099f515 ansi256=0ee389babd62 html=b09e98948277
416-34/159 a8c9c943771f1bac64729951416+34/159 input=b65ddcd437b9 vt=540ab8b4a6d9 graphics=71afa643a19e history=95e19294a4cb ansi=e1cdb7e662c3 ansi256=733d11b8083f html=83f8842bbd2e
417-34/179 147dc1d5ce1aa53965747a76417+34/179 input=57f1f81acb3c vt=41ece03f7923 graphics=7dc07edadc7a history=ce5abe9435b7 ansi=7d026cc1a611 ansi256=15f91df0de54 html=01710e6ff318
418-34/199 d60cdab9e926b1a975ab7c68418+34/199 input=3a7b3c2440bf vt=a9150ba7a4cb graphics=52db9cf3851a history=e14f94ccdd58 ansi=2a2474a89a60 ansi256=0537f46cd650 html=295390e7c9e6
419-34/219 70311db1c213b30d8622a677419+34/219 input=76c4c4ccc65d vt=ac0da0319944 graphics=59162dcc7a6c history=3f8c45dc183b ansi=49a40bf933cf ansi256=15bd13cb4377 html=d356d7e4aec0
420-34/239 16c8a61f803eef432762550b420+34/239 input=74a38b340785 vt=754f065a06b1 graphics=784b8e4a91be history=8af536dda7f7 ansi=a858ae00e59d ansi256=dd5c4ca64682 html=a77267367f14
421-35/019 6ce6075f205b75f864a11ca6421+35/019 input=e01695bf4e50 vt=8d5a98309b21 graphics=023952274cf9 history=2659734a87a8 ansi=b024edea8c61 ansi256=d5f38420be8b html=3515ae8035f2
422-35/039 8375248e74a353fc4ec62d73422+35/039 input=93665be63313 vt=a35f7be82f67 graphics=18b07a725813 history=7e0e18d77c74 ansi=390a8472c45c ansi256=6f6a93364ee3 html=8ae2d5763ebb
423-35/059 794e546c0d3346dc3965043f423+35/059 input=dd1cc03b3572 vt=6afa913190d6 graphics=14547246cfc9 history=be2e3ffa555b ansi=31f3ce2ba63c ansi256=3884c9872e16 html=3444412498cd
424-35/079 f4a4a12dd0c59cfa3a7036b4424+35/079 input=44796a406918 vt=6ce22280a030 graphics=8244d770854a history=30ab815d28f1 ansi=02a0bdfbbcd6 ansi256=8eb3b5dd6ca5 html=035d2d2e090f
425-35/099 a424a229392a35da8d937062425+35/099 input=43ec30d13ab6 vt=13cafa9a15c4 graphics=c8de2510382b history=de35b2cda662 ansi=18856574b289 ansi256=803599ee7085 html=20449628df2c
426-35/119 5e71329265c6c2ddfdebda4d426+35/119 input=51d29207da68 vt=cc52140c5b87 graphics=569a06ba1c26 history=ae9194ed626a ansi=3d3a69a1cec5 ansi256=a619ec705a9b html=2f61a9b55f28
427-35/139 6aa980472b2f18fe51c96a53427+35/139 input=b6e1eac19c21 vt=87bc9c96ee66 graphics=a761438c266b history=c565c9eb5e67 ansi=8b92e0851a34 ansi256=4ffa0b70b26c html=89caf046d441
428-35/159 c677d854790176770b89c39b428+35/159 input=b720c6dc8986 vt=5460691c9f91 graphics=1b8ce71ffdce history=6dfd322c6901 ansi=1728d0c18bca ansi256=b7b1df41146f html=72290758bc08
429-35/179 aa982fd9d111a2bfe2cd0342429+35/179 input=0341f9cb3b4d vt=7336edcff9a8 graphics=ff521966f503 history=c556c9bddb2d ansi=df31635476c2 ansi256=2259657c5fb8 html=85bd9cee86c2
430-35/199 ce9d070f4fa6d77de1426eca430+35/199 input=1f9be1f8195d vt=e1efb6275a87 graphics=806918fdf91b history=c577342a7558 ansi=0d61fc403ed4 ansi256=3dfe6c2d3f95 html=79cf3e389d27
431-35/219 a867713adf7f878aaac51716431+35/219 input=1706e3dc7ba6 vt=4797a5f1c73a graphics=9c0eb19d32f4 history=9448c87c1fde ansi=4093919d80c9 ansi256=e8391c2d9989 html=0398443da2dd
432-35/239 336185b759391ae1b9650572432+35/239 input=880a5d50813f vt=06531473f963 graphics=0dc2013efaf5 history=449d96644a4f ansi=250e7eeabc3c ansi256=4c6fafe74d13 html=464da1cb9915

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 13

↑↓ moveenter openesc close