- commit
- 9f59fd13428f87ffb12be79ac5a5400c8e173e38
- parent
- 617ab46de68e6dd2d8acf206e5aefcc24c95f5e8
- author
- Dami <dami.etoile@gmail.com>
- kind
- test risk score 1.4 of 3, Jev's estimate
@@ -112,6 +112,9 @@ ASCII are compared by case.
112112 113113 ## Formulas over a source114114 115+116+117+115118 A function given a source's range is worked out in the background, by116119 reading the source; its cell shows `Loading…` until then. The answer117120 is kept until the file changes, so another formula asking the same, orBinary file.
Binary file.
Binary file.
Binary file.
@@ -9,13 +9,23 @@ require (
99 )1010 1111 require (12+ github.com/andybalholm/brotli v1.1.1 // indirect13+ github.com/google/uuid v1.6.0 // indirect14+ github.com/klauspost/compress v1.17.9 // indirect15+ github.com/parquet-go/bitpack v1.0.0 // indirect16+ github.com/parquet-go/jsonlite v1.0.0 // indirect17+ github.com/parquet-go/parquet-go v0.32.0 // indirect18+ github.com/pierrec/lz4/v4 v4.1.21 // indirect1219 github.com/richardlehane/mscfb v1.0.7 // indirect1320 github.com/richardlehane/msoleps v1.0.6 // indirect1421 github.com/tiendc/go-deepcopy v1.7.2 // indirect22+ github.com/twpayne/go-geom v1.6.1 // indirect1523 github.com/xuri/efp v0.0.1 // indirect1624 github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect1725 golang.org/x/crypto v0.53.0 // indirect1826 golang.org/x/image v0.45.0 // indirect1927 golang.org/x/net v0.56.0 // indirect28+ golang.org/x/sys v0.47.0 // indirect2029 golang.org/x/text v0.41.0 // indirect30+ google.golang.org/protobuf v1.34.2 // indirect2131 )@@ -1,7 +1,21 @@
1+github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=2+github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=13 github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=24 github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=35 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=46 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=7+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=8+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=9+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=10+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=11+github.com/parquet-go/bitpack v1.0.0 h1:AUqzlKzPPXf2bCdjfj4sTeacrUwsT7NlcYDMUQxPcQA=12+github.com/parquet-go/bitpack v1.0.0/go.mod h1:XnVk9TH+O40eOOmvpAVZ7K2ocQFrQwysLMnc6M/8lgs=13+github.com/parquet-go/jsonlite v1.0.0 h1:87QNdi56wOfsE5bdgas0vRzHPxfJgzrXGml1zZdd7VU=14+github.com/parquet-go/jsonlite v1.0.0/go.mod h1:nDjpkpL4EOtqs6NQugUsi0Rleq9sW/OtC1NnZEnxzF0=15+github.com/parquet-go/parquet-go v0.32.0 h1:NWDqTUHfrCS4cJP/Fj2HlxvqsrVedWG3sayMkf+znzM=16+github.com/parquet-go/parquet-go v0.32.0/go.mod h1:navtkAYr2LGoJVp141oXPlO/sxLvaOe3la2JEoD8+rg=17+github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=18+github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=519 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=620 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=721 github.com/richardlehane/mscfb v1.0.7 h1:oeoiM0WE79vHwE8RpIYYvIAc8ajTH2mb6UZm55/+EB0=@@ -12,12 +26,15 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
1226 github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=1327 github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=1428 github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=29+github.com/twpayne/go-geom v1.6.1 h1:iLE+Opv0Ihm/ABIcvQFGIiFBXd76oBIar9drAwHFhR4=30+github.com/twpayne/go-geom v1.6.1/go.mod h1:Kr+Nly6BswFsKM5sd31YaoWS5PeDDH2NftJTK7Gd028=1531 github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=1632 github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=1733 github.com/xuri/excelize/v2 v2.11.0 h1:HxaEFl6sRN2+8J5a8HaKq+0M4FsjBGMnWWtjOCPSG88=1834 github.com/xuri/excelize/v2 v2.11.0/go.mod h1:jxFLbzaIwGQ5ufFNvYfUOHqXhfPaNmP14KWfmNz2Uak=1935 github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=2036 github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=37+github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=2138 go.mitchellh.com/libghostty v0.0.0-20260920220152-31b65cdc24cf h1:PgfZ7mRcXk8n3+B+46oo9WxDi6xK1z6feOQEKNRWCBs=2239 go.mitchellh.com/libghostty v0.0.0-20260920220152-31b65cdc24cf/go.mod h1:sx8yDvnDrQC/PzsrFfYx7ROmH8my91nz7lOxQb6sbo0=2340 golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=@@ -28,9 +45,13 @@ golang.org/x/image v0.45.0 h1:FMb1nTbH5H9vF55SriQHgFw5GnNL9Jg6L25BwXKzhB0=
2845 golang.org/x/image v0.45.0/go.mod h1:n62x/7RqlwXDvGsSU4u6IUTUf6KghUZ9Bt7cG/T9Fx4=2946 golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=3047 golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=48+golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=49+golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=3150 golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=3251 golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=3352 golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=3453 golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=54+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=55+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=3556 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=3657 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=@@ -0,0 +1,102 @@
1+package e2e2+3+import (4+ "path/filepath"5+ "strings"6+ "testing"7+8+ ghostty "go.mitchellh.com/libghostty"9+)10+11+// Golden screens for linked sources: two million trips on a tab of12+// their own, sorted by fare and scrolled halfway down by the scrollbar;13+// formulas over them on a sheet, one past max-cells saying why; the14+// condition a source's column is filtered by; and a source whose file15+// isn't there. Each on a light terminal too, the tab in the high-contrast16+// theme as well.17+18+func tripsFile(t *testing.T, dir string) { writeTrips(t, dir, tripRows) }19+20+// sortedTrips links trips.parquet, sorts it by fare Z to A and drags21+// the scrollbar halfway down.22+func sortedTrips(s *session) {23+ s.linkSource("trips.parquet")24+ s.waitFor("2,000,000 rows, 5 columns")25+ s.keys("<right>", "<right>")26+ s.keys("<ctrl+k>", "Sort sheet Z to A", "<enter>")27+ s.waitFor("sorted by fare Z to A")28+ s.waitFor("92.99")29+ bar := int(s.cols) - 130+ top, bottom := 7, int(s.rows)-231+ s.click(ghostty.MouseButtonLeft, bar, (top+bottom)/2)32+ s.waitFor("┃")33+ s.eventually("the rows halfway down", func() bool {34+ return strings.Contains(s.line(1), " 48") && !strings.Contains(s.screen(), " … ")35+ })36+}37+38+// tripFormulas reads the trips from a sheet: counts, sums, a lookup,39+// and a MEDIAN past max-cells (a million, in the screen's config),40+// the pointer on it.41+func tripFormulas(s *session) {42+ s.linkSource("trips.parquet")43+ s.keys("<ctrl+pgup>")44+ s.waitFor("Sheet1")45+ for _, row := range [][2]string{46+ {"Trips", "=ROWS(trips)"},47+ {"Fares", "=SUM(trips[fare])"},48+ {"By card", `=SUMIFS(trips[fare],trips[payment],"card")`},49+ {"Vouchers", `=COUNTIF(trips[payment],"voucher")`},50+ {"Longest", "=MAX(trips[miles])"},51+ {"Trip 1M", "=XLOOKUP(1000000,trips[trip],trips[fare])"},52+ {"Median", "=MEDIAN(trips[fare])"},53+ } {54+ s.keys(row[0], "<tab>", row[1], "<enter>")55+ }56+ s.waitFor("285714")57+ s.waitFor("#VALUE!")58+ s.keys("<up>", "<right>")59+ s.waitFor("MEDIAN would hold")60+}61+62+var sourceScreens = []screen{63+ {name: "source-tab", files: tripsFile, setup: sortedTrips},64+ {name: "source-formulas", opts: options{config: "max-cells = 1000000\n"}, files: tripsFile, setup: tripFormulas},65+ {name: "source-filter", files: tripsFile, setup: func(s *session) {66+ s.linkSource("trips.parquet")67+ s.waitFor("card")68+ s.keys("<right>")69+ s.keys("<ctrl+k>", "Filter by column", "<enter>")70+ s.waitFor("Filter B payment")71+ for range 7 {72+ s.keys("<down>")73+ }74+ s.keys("card")75+ s.waitFor("Text is exactly")76+ s.waitFor("card ")77+ }},78+ {name: "source-missing", files: func(t *testing.T, dir string) {79+ writeText(t, filepath.Join(dir, "rides.012"),80+ `{"version": 7, "sheets": [{"name": "Sheet1", "cells": {"A1": "=SUM(trips[fare])"}}, `+81+ `{"name": "trips", "cells": {}, "regions": [{"name": "trips", "at": "A1", "path": "trips.parquet", "paged": true}]}]}`)82+ }, args: []string{"rides.012"}, setup: func(s *session) {83+ s.waitFor("#REF!")84+ s.keys("<ctrl+pgdown>")85+ s.waitFor("! trips.parquet: the file isn't there")86+ }},87+}88+89+func init() {90+ for _, sc := range sourceScreens {91+ light := sc92+ light.name += "-light"93+ light.opts.light = true94+ screens = append(screens, sc, light)95+ if sc.name == "source-tab" {96+ hc := sc97+ hc.name += "-high-contrast"98+ hc.opts.config = highContrastConfig99+ screens = append(screens, hc)100+ }101+ }102+}@@ -0,0 +1,113 @@
1+package e2e2+3+import (4+ "fmt"5+ "os"6+ "path/filepath"7+ "strings"8+ "testing"9+ "time"10+11+ "github.com/parquet-go/parquet-go"12+)13+14+// trip is a row of the Parquet file the linked sources' tests read: a15+// ride, how it was paid, its fare, its miles and its day.16+type trip struct {17+ Trip int64 `parquet:"trip"`18+ Payment string `parquet:"payment,dict"`19+ Fare float64 `parquet:"fare"`20+ Miles float64 `parquet:"miles"`21+ Day int32 `parquet:"day,date"`22+}23+24+// payments are the ways trips are paid, in the order rows take them.25+var payments = []string{"card", "cash", "card", "app", "card", "cash", "voucher"}26+27+// tripAt is trip i, the same whenever it's asked for.28+func tripAt(i int) trip {29+ day := int32(time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC).Unix()/86400) + int32(i%270)30+ return trip{Trip: int64(i + 1), Payment: payments[i%len(payments)],31+ Fare: float64((i*7919)%9000)/100 + 3, Miles: float64((i*104729)%400) / 10, Day: day}32+}33+34+// writeTrips writes rows trips to trips.parquet in dir.35+func writeTrips(t *testing.T, dir string, rows int) {36+ t.Helper()37+ f, err := os.Create(filepath.Join(dir, "trips.parquet"))38+ if err != nil {39+ t.Fatal(err)40+ }41+ defer f.Close()42+ w := parquet.NewGenericWriter[trip](f, parquet.MaxRowsPerRowGroup(1<<18))43+ batch := make([]trip, 1<<14)44+ for i := 0; i < rows; i += len(batch) {45+ n := min(len(batch), rows-i)46+ for j := range n {47+ batch[j] = tripAt(i + j)48+ }49+ if _, err := w.Write(batch[:n]); err != nil {50+ t.Fatal(err)51+ }52+ }53+ if err := w.Close(); err != nil {54+ t.Fatal(err)55+ }56+}57+58+// tripRows is how many rows the screens' source has: past the grid's59+// last row.60+const tripRows = 2_000_00061+62+// linkSource links name as a source through the palette, and waits for63+// its rows.64+func (s *session) linkSource(name string) {65+ s.t.Helper()66+ s.keys("<ctrl+k>", "Link a source")67+ s.waitFor("Link a source")68+ s.keys("<enter>")69+ s.waitFor("Type to filter, or a path")70+ s.keys(name, "<enter>")71+ s.waitFor("Linked " + name)72+ s.keys("<down>", "<up>") // the note gives way to the source's line73+ s.waitFor("▦ " + name)74+}75+76+func TestLinkedSource(t *testing.T) {77+ dir := t.TempDir()78+ writeTrips(t, dir, tripRows)79+ s := start(t, dir)80+ s.linkSource("trips.parquet")81+ s.waitFor("2,000,000 rows, 5 columns")82+ s.waitFor("card")83+84+ // The last row, numbered past the grid's last row.85+ s.keys("<ctrl+down>")86+ s.waitFor("2000001 ")87+88+ // Sorted by fare, Z to A, in the background.89+ s.keys("<ctrl+home>", "<right>", "<right>")90+ s.keys("<ctrl+k>", "Sort sheet Z to A", "<enter>")91+ s.waitFor("sorted by fare Z to A")92+ s.eventually("the top fare", func() bool { return strings.Contains(s.line(1), "92.99") })93+94+ // A formula on another sheet reads the whole source.95+ s.keys("<ctrl+pgup>")96+ s.waitFor("Sheet1")97+ s.keys("=COUNTIF(trips[payment],\"voucher\")", "<enter>")98+ s.waitFor(fmt.Sprint(tripRows / 7))99+100+ // Saved, the workbook keeps the link, and reads the source again.101+ s.keys("<ctrl+s>")102+ s.waitFor("Save as:")103+ s.keys("rides", "<enter>")104+ s.waitFor("rides.012")105+ data, err := os.ReadFile(filepath.Join(dir, "rides.012"))106+ if err != nil || !strings.Contains(string(data), `"paged":true`) || !strings.Contains(string(data), `"version": 7`) {107+ t.Fatalf("the file: %v\n%s", err, data)108+ }109+ s.keys("<ctrl+q>")110+ s.waitExit()111+ s = start(t, dir, "rides.012")112+ s.waitFor(fmt.Sprint(tripRows / 7))113+}@@ -38,6 +38,8 @@ var docScreens = []docScreen{
3838 {name: "notebook-nu-error", from: "notebook-nu-error", cols: 80, rows: 16},3939 {name: "notebook-grid", from: "notebook-grid", cols: 80, rows: 24},4040 {name: "share-presence", from: "share-presence", cols: 80, rows: 13},41+ {name: "source-tab", from: "source-tab", cols: 80, rows: 20},42+ {name: "source-formulas", from: "source-formulas", cols: 80, rows: 14},4143 }4244 4345 // stillsVersion changes when the drawing does, so every still is@@ -145,6 +145,13 @@ var symbols = map[rune]func(y symbol){
145145 '✓': func(y symbol) { y.line(.12, .14, .54, .4, .8, .88, .2) },146146 '✗': func(y symbol) { y.line(.12, .2, .2, .8, .8); y.line(.12, .8, .2, .2, .8) },147147 '❯': func(y symbol) { y.line(.16, .3, .16, .72, .5, .3, .84) },148+ '▦': func(y symbol) {149+ y.box(.1, .1, .9, .9, .08)150+ y.line(.06, .1, .37, .9, .37)151+ y.line(.06, .1, .63, .9, .63)152+ y.line(.06, .37, .1, .37, .9)153+ y.line(.06, .63, .1, .63, .9)154+ },148155 '⧉': func(y symbol) { y.box(.08, .08, .64, .64, .08); y.box(.36, .36, .92, .92, .08) },149156 '⎘': func(y symbol) { y.box(.16, .16, .84, .94, .08); y.rect(.34, .04, .66, .26) },150157 '↻': reload,@@ -0,0 +1,14 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B7</span><span style="background:var(--vt-palette-7)"> </span> =MEDIAN(trips[fare])3+<span style="color:var(--vt-palette-1)">#VALUE!</span> <span style="color:var(--vt-palette-0)">MEDIAN</span> <span style="color:var(--vt-palette-0)">would</span> <span style="color:var(--vt-palette-0)">hold</span> <span style="color:var(--vt-palette-0)">2,000,000</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">trips,</span> <span style="color:var(--vt-palette-0)">past</span> <span style="color:var(--vt-palette-0)">max-cells</span> <span style="color:var(--vt-palette-0)">(1,000,000):</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Trips 20000006+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Fares 959900007+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> By card 411385638+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Vouchers 2857149+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Longest 39.910+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Trip 1M 3.8111+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Median <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline wavy var(--vt-palette-1)">#VALUE!</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Sheet1</span><span style="background:var(--vt-palette-6)"> </span> ▦ trips <span style="color:var(--vt-palette-0)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span></pre>\ No newline at end of file@@ -0,0 +1,14 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B7</span><span style="background:var(--vt-palette-8)"> </span> =MEDIAN(trips[fare])3+<span style="color:var(--vt-palette-1)">#VALUE!</span> <span style="color:var(--vt-palette-8)">MEDIAN</span> <span style="color:var(--vt-palette-8)">would</span> <span style="color:var(--vt-palette-8)">hold</span> <span style="color:var(--vt-palette-8)">2,000,000</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">trips,</span> <span style="color:var(--vt-palette-8)">past</span> <span style="color:var(--vt-palette-8)">max-cells</span> <span style="color:var(--vt-palette-8)">(1,000,000):</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Trips 20000006+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Fares 959900007+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> By card 411385638+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Vouchers 2857149+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Longest 39.910+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> Trip 1M 3.8111+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Median <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline wavy var(--vt-palette-1)">#VALUE!</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span>14+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Sheet1</span><span style="background:var(--vt-palette-6)"> </span> ▦ trips <span style="color:var(--vt-palette-8)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+K</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">search</span></pre>\ No newline at end of file@@ -0,0 +1,20 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">SOURCE</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C1912502</span><span style="background:var(--vt-palette-7)"> </span> 483+<span style="color:var(--vt-palette-0)">▦</span> <span style="font-weight:bold">trips.parquet</span> <span style="color:var(--vt-palette-0)">2,000,000</span> <span style="color:var(--vt-palette-0)">rows,</span> <span style="color:var(--vt-palette-0)">5</span> <span style="color:var(--vt-palette-0)">columns;</span> <span style="color:var(--vt-palette-0)">sorted</span> <span style="color:var(--vt-palette-0)">by</span> <span style="color:var(--vt-palette-0)">fare</span> <span style="color:var(--vt-palette-0)">Z</span> <span style="color:var(--vt-palette-0)">to</span> <span style="color:var(--vt-palette-0)">A</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">C</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">trip</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">payment</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">fare</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">miles</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">day</span><span style="text-decoration:underline"> </span>6+<span style="color:var(--vt-palette-8)">────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1912502</span><span style="background:var(--vt-palette-6)"> </span>1912501 card <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">48</span><span style="background:var(--vt-palette-6)"> </span> 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1921502</span><span style="background:var(--vt-palette-7)"> </span>1921501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1930502</span><span style="background:var(--vt-palette-7)"> </span>1930501 cash 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1939502</span><span style="background:var(--vt-palette-7)"> </span>1939501 app 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1948502</span><span style="background:var(--vt-palette-7)"> </span>1948501 cash 48 10 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1957502</span><span style="background:var(--vt-palette-7)"> </span>1957501 voucher 48 30 1/1/2026 <span style="font-weight:bold">┃</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1966502</span><span style="background:var(--vt-palette-7)"> </span>1966501 card 48 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1975502</span><span style="background:var(--vt-palette-7)"> </span>1975501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1984502</span><span style="background:var(--vt-palette-7)"> </span>1984501 card 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1993502</span><span style="background:var(--vt-palette-7)"> </span>1993501 cash 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8823</span><span style="background:var(--vt-palette-7)"> </span> 8822 cash 47.99 10.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17823</span><span style="background:var(--vt-palette-7)"> </span> 17822 voucher 47.99 30.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>19+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">26823</span><span style="background:var(--vt-palette-7)"> </span> 26822 card 47.99 10.9 4/2/2026 <span style="color:var(--vt-palette-8)">│</span>20+ Sheet1 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">▦</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">trips</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-0)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span></pre>\ No newline at end of file@@ -0,0 +1,20 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">SOURCE</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C1912502</span><span style="background:var(--vt-palette-8)"> </span> 483+<span style="color:var(--vt-palette-8)">▦</span> <span style="font-weight:bold">trips.parquet</span> <span style="color:var(--vt-palette-8)">2,000,000</span> <span style="color:var(--vt-palette-8)">rows,</span> <span style="color:var(--vt-palette-8)">5</span> <span style="color:var(--vt-palette-8)">columns;</span> <span style="color:var(--vt-palette-8)">sorted</span> <span style="color:var(--vt-palette-8)">by</span> <span style="color:var(--vt-palette-8)">fare</span> <span style="color:var(--vt-palette-8)">Z</span> <span style="color:var(--vt-palette-8)">to</span> <span style="color:var(--vt-palette-8)">A</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">C</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">trip</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">payment</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">fare</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">miles</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">day</span><span style="text-decoration:underline"> </span>6+<span style="color:var(--vt-palette-8)">────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1912502</span><span style="background:var(--vt-palette-6)"> </span>1912501 card <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">48</span><span style="background:var(--vt-palette-6)"> </span> 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1921502</span><span style="background:var(--vt-palette-8)"> </span>1921501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1930502</span><span style="background:var(--vt-palette-8)"> </span>1930501 cash 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1939502</span><span style="background:var(--vt-palette-8)"> </span>1939501 app 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1948502</span><span style="background:var(--vt-palette-8)"> </span>1948501 cash 48 10 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1957502</span><span style="background:var(--vt-palette-8)"> </span>1957501 voucher 48 30 1/1/2026 <span style="font-weight:bold">┃</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1966502</span><span style="background:var(--vt-palette-8)"> </span>1966501 card 48 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1975502</span><span style="background:var(--vt-palette-8)"> </span>1975501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1984502</span><span style="background:var(--vt-palette-8)"> </span>1984501 card 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1993502</span><span style="background:var(--vt-palette-8)"> </span>1993501 cash 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8823</span><span style="background:var(--vt-palette-8)"> </span> 8822 cash 47.99 10.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17823</span><span style="background:var(--vt-palette-8)"> </span> 17822 voucher 47.99 30.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>19+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">26823</span><span style="background:var(--vt-palette-8)"> </span> 26822 card 47.99 10.9 4/2/2026 <span style="color:var(--vt-palette-8)">│</span>20+ Sheet1 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">▦</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">trips</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-8)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+K</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">search</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">FILTER</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B2</span><span style="background:var(--vt-palette-7)"> </span> card3+4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">trip</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Filter</span> <span style="font-weight:bold">B</span> <span style="font-weight:bold">payment</span> <span style="color:var(--vt-palette-8)">────────────────┐</span>6+<span style="color:var(--vt-palette-8)">───────────────│</span> <span style="color:var(--vt-palette-0)">If</span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">‹</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Text</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">is</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">exactly</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">›</span> card <span style="color:var(--vt-palette-8)">│───────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">2</span><span style="background:var(--vt-palette-6)"> </span> 1 <span style="color:var(--vt-palette-8)">└────────────────────────────────────┘</span> <span style="font-weight:bold">┃</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> 2 cash 82.19 32.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> 3 card 71.38 25.8 1/3/2026 <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> 4 app 60.57 18.7 1/4/2026 <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> 5 card 49.76 11.6 1/5/2026 <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> 6 cash 38.95 4.5 1/6/2026 <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> 7 voucher 28.14 37.4 1/7/2026 <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> 8 card 17.33 30.3 1/8/2026 <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> 9 cash 6.52 23.2 1/9/2026 <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> 10 card 85.71 16.1 1/10/2026 <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> 11 app 74.9 9 1/11/2026 <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> 12 card 64.09 1.9 1/12/2026 <span style="color:var(--vt-palette-8)">│</span>19+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> 13 cash 53.28 34.8 1/13/2026 <span style="color:var(--vt-palette-8)">│</span>20+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> 14 voucher 42.47 27.7 1/14/2026 <span style="color:var(--vt-palette-8)">│</span>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span> 15 card 31.66 20.6 1/15/2026 <span style="color:var(--vt-palette-8)">│</span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span> 16 cash 20.85 13.5 1/16/2026 <span style="color:var(--vt-palette-8)">│</span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span> 17 card 10.04 6.4 1/17/2026 <span style="color:var(--vt-palette-8)">│</span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span> 18 app 89.23 39.3 1/18/2026 <span style="color:var(--vt-palette-8)">│</span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span> 19 card 78.42 32.2 1/19/2026 <span style="color:var(--vt-palette-8)">│</span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span> 20 cash 67.61 25.1 1/20/2026 <span style="color:var(--vt-palette-8)">│</span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span> 21 voucher 56.8 18 1/21/2026 <span style="color:var(--vt-palette-8)">│</span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span> 22 card 45.99 10.9 1/22/2026 <span style="color:var(--vt-palette-8)">│</span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span> 23 cash 35.18 3.8 1/23/2026 <span style="color:var(--vt-palette-8)">│</span>30+Rows must meet the condition <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Up/Down</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">condition</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">apply</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">cancel</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">FILTER</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B2</span><span style="background:var(--vt-palette-8)"> </span> card3+4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">trip</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Filter</span> <span style="font-weight:bold">B</span> <span style="font-weight:bold">payment</span> <span style="color:var(--vt-palette-8)">────────────────┐</span>6+<span style="color:var(--vt-palette-8)">───────────────│</span> <span style="color:var(--vt-palette-8)">If</span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">‹</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Text</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">is</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">exactly</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">›</span> card <span style="color:var(--vt-palette-8)">│───────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">2</span><span style="background:var(--vt-palette-6)"> </span> 1 <span style="color:var(--vt-palette-8)">└────────────────────────────────────┘</span> <span style="font-weight:bold">┃</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> 2 cash 82.19 32.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> 3 card 71.38 25.8 1/3/2026 <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> 4 app 60.57 18.7 1/4/2026 <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> 5 card 49.76 11.6 1/5/2026 <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> 6 cash 38.95 4.5 1/6/2026 <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> 7 voucher 28.14 37.4 1/7/2026 <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> 8 card 17.33 30.3 1/8/2026 <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> 9 cash 6.52 23.2 1/9/2026 <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> 10 card 85.71 16.1 1/10/2026 <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> 11 app 74.9 9 1/11/2026 <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> 12 card 64.09 1.9 1/12/2026 <span style="color:var(--vt-palette-8)">│</span>19+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> 13 cash 53.28 34.8 1/13/2026 <span style="color:var(--vt-palette-8)">│</span>20+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> 14 voucher 42.47 27.7 1/14/2026 <span style="color:var(--vt-palette-8)">│</span>21+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> 15 card 31.66 20.6 1/15/2026 <span style="color:var(--vt-palette-8)">│</span>22+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17</span><span style="background:var(--vt-palette-8)"> </span> 16 cash 20.85 13.5 1/16/2026 <span style="color:var(--vt-palette-8)">│</span>23+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">18</span><span style="background:var(--vt-palette-8)"> </span> 17 card 10.04 6.4 1/17/2026 <span style="color:var(--vt-palette-8)">│</span>24+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">19</span><span style="background:var(--vt-palette-8)"> </span> 18 app 89.23 39.3 1/18/2026 <span style="color:var(--vt-palette-8)">│</span>25+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">20</span><span style="background:var(--vt-palette-8)"> </span> 19 card 78.42 32.2 1/19/2026 <span style="color:var(--vt-palette-8)">│</span>26+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">21</span><span style="background:var(--vt-palette-8)"> </span> 20 cash 67.61 25.1 1/20/2026 <span style="color:var(--vt-palette-8)">│</span>27+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">22</span><span style="background:var(--vt-palette-8)"> </span> 21 voucher 56.8 18 1/21/2026 <span style="color:var(--vt-palette-8)">│</span>28+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">23</span><span style="background:var(--vt-palette-8)"> </span> 22 card 45.99 10.9 1/22/2026 <span style="color:var(--vt-palette-8)">│</span>29+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">24</span><span style="background:var(--vt-palette-8)"> </span> 23 cash 35.18 3.8 1/23/2026 <span style="color:var(--vt-palette-8)">│</span>30+Rows must meet the condition <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Up/Down</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">condition</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Enter</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">apply</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Esc</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">cancel</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B7</span><span style="background:var(--vt-palette-7)"> </span> =MEDIAN(trips[fare])3+<span style="color:var(--vt-palette-1)">#VALUE!</span> <span style="color:var(--vt-palette-0)">MEDIAN</span> <span style="color:var(--vt-palette-0)">would</span> <span style="color:var(--vt-palette-0)">hold</span> <span style="color:var(--vt-palette-0)">2,000,000</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">trips,</span> <span style="color:var(--vt-palette-0)">past</span> <span style="color:var(--vt-palette-0)">max-cells</span> <span style="color:var(--vt-palette-0)">(1,000,000):</span> <span style="color:var(--vt-palette-0)">SUMIFS,</span> <span style="color:var(--vt-palette-0)">XLOOKUP</span> <span style="color:var(--vt-palette-0)">and</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Trips 20000006+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Fares 959900007+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> By card 411385638+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Vouchers 2857149+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Longest 39.910+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Trip 1M 3.8111+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Median <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline wavy var(--vt-palette-1)">#VALUE!</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span>15+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span>16+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span>18+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span>19+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span>20+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Sheet1</span><span style="background:var(--vt-palette-6)"> </span> ▦ trips <span style="color:var(--vt-palette-0)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B7</span><span style="background:var(--vt-palette-8)"> </span> =MEDIAN(trips[fare])3+<span style="color:var(--vt-palette-1)">#VALUE!</span> <span style="color:var(--vt-palette-8)">MEDIAN</span> <span style="color:var(--vt-palette-8)">would</span> <span style="color:var(--vt-palette-8)">hold</span> <span style="color:var(--vt-palette-8)">2,000,000</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">trips,</span> <span style="color:var(--vt-palette-8)">past</span> <span style="color:var(--vt-palette-8)">max-cells</span> <span style="color:var(--vt-palette-8)">(1,000,000):</span> <span style="color:var(--vt-palette-8)">SUMIFS,</span> <span style="color:var(--vt-palette-8)">XLOOKUP</span> <span style="color:var(--vt-palette-8)">and</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">I</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Trips 20000006+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Fares 959900007+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> By card 411385638+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Vouchers 2857149+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Longest 39.910+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> Trip 1M 3.8111+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Median <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline wavy var(--vt-palette-1)">#VALUE!</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span>14+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span>19+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span>20+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span>21+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17</span><span style="background:var(--vt-palette-8)"> </span>22+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">18</span><span style="background:var(--vt-palette-8)"> </span>23+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">19</span><span style="background:var(--vt-palette-8)"> </span>24+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">20</span><span style="background:var(--vt-palette-8)"> </span>25+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">21</span><span style="background:var(--vt-palette-8)"> </span>26+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">22</span><span style="background:var(--vt-palette-8)"> </span>27+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">23</span><span style="background:var(--vt-palette-8)"> </span>28+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">24</span><span style="background:var(--vt-palette-8)"> </span>29+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">25</span><span style="background:var(--vt-palette-8)"> </span>30+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Sheet1</span><span style="background:var(--vt-palette-6)"> </span> ▦ trips <span style="color:var(--vt-palette-8)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+K</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">search</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+/</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">shortcuts</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">menu</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">SOURCE</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A1</span><span style="background:var(--vt-palette-7)"> </span>3+<span style="color:var(--vt-palette-3)">!</span> <span style="color:var(--vt-palette-3)">trips.parquet:</span> <span style="color:var(--vt-palette-3)">the</span> <span style="color:var(--vt-palette-3)">file</span> <span style="color:var(--vt-palette-3)">isn't</span> <span style="color:var(--vt-palette-3)">there</span>4+<span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span>6+<span style="color:var(--vt-palette-8)">────────────────────────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>8+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>9+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>10+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>11+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>12+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>13+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>14+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>15+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>16+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>17+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>18+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>19+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>20+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>21+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>22+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>23+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>24+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>25+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>26+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>27+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>28+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>29+<span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">┃</span>30+ Sheet1 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">▦</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">trips</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">!</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-0)">+</span> <span style="color:var(--vt-palette-8)">│</span> rides.012 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">SOURCE</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A1</span><span style="background:var(--vt-palette-8)"> </span>3+<span style="color:var(--vt-palette-3)">!</span> <span style="color:var(--vt-palette-3)">trips.parquet:</span> <span style="color:var(--vt-palette-3)">the</span> <span style="color:var(--vt-palette-3)">file</span> <span style="color:var(--vt-palette-3)">isn't</span> <span style="color:var(--vt-palette-3)">there</span>4+<span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span>6+<span style="color:var(--vt-palette-8)">────────────────────────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>8+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>9+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>10+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>11+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>12+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>13+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>14+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>15+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>16+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>17+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>18+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>19+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>20+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>21+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>22+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>23+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>24+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>25+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>26+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>27+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>28+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>29+<span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">┃</span>30+ Sheet1 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">▦</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">trips</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">!</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-8)">+</span> <span style="color:var(--vt-palette-8)">│</span> rides.012 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+K</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">search</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+/</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">shortcuts</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">menu</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">F</span><span style="color:#ffffff;background:#1f1f1f">ile</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">E</span><span style="color:#ffffff;background:#1f1f1f">dit</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">V</span><span style="color:#ffffff;background:#1f1f1f">iew</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">I</span><span style="color:#ffffff;background:#1f1f1f">nsert</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f">F</span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">o</span><span style="color:#ffffff;background:#1f1f1f">rmat</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">D</span><span style="color:#ffffff;background:#1f1f1f">ata</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f;text-decoration:underline">H</span><span style="color:#ffffff;background:#1f1f1f">elp</span><span style="background:#1f1f1f"> </span><span style="background:#40e0ff"> </span><span style="color:#000000;background:#40e0ff;font-weight:bold">SOURCE</span><span style="background:#40e0ff"> </span>2+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">C1867502</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span>3+<span style="color:#959595;background:#000000">▦</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000;font-weight:bold">trips.parquet</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">2,000,000</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">rows,</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">5</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">columns;</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">sorted</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">by</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">fare</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">Z</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">to</span><span style="background:#000000"> </span><span style="color:#959595;background:#000000">A</span><span style="background:#000000"> </span>4+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">A</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">B</span><span style="background:#3a3a3a"> </span><span style="background:#40e0ff"> </span><span style="color:#000000;background:#40e0ff;font-weight:bold">C</span><span style="background:#40e0ff"> </span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">D</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">E</span><span style="background:#3a3a3a"> </span>5+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1</span><span style="background:#3a3a3a"> </span><span style="background:#000000;text-decoration:underline"> </span><span style="color:#40e0ff;background:#000000;font-weight:bold;text-decoration:underline">trip</span><span style="background:#000000;text-decoration:underline"> </span><span style="color:#40e0ff;background:#000000;font-weight:bold;text-decoration:underline">payment</span><span style="background:#000000;text-decoration:underline"> </span><span style="color:#40e0ff;background:#000000;font-weight:bold;text-decoration:underline">fare</span><span style="background:#000000;text-decoration:underline"> </span><span style="color:#40e0ff;background:#000000;font-weight:bold;text-decoration:underline">miles</span><span style="background:#000000;text-decoration:underline"> </span><span style="color:#40e0ff;background:#000000;font-weight:bold;text-decoration:underline">day</span><span style="background:#000000;text-decoration:underline"> </span><span style="background:#000000"> </span>6+<span style="color:#757575;background:#000000">────────────────────────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:#40e0ff"> </span><span style="color:#000000;background:#40e0ff;font-weight:bold">1867502</span><span style="background:#40e0ff"> </span><span style="color:#ffffff;background:#000000">1867501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="background:#40e0ff"> </span><span style="color:#000000;background:#40e0ff">48</span><span style="background:#40e0ff"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">6/30/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>8+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1876502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1876501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">app</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>9+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1885502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1885501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>10+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1894502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1894501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">voucher</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">6/30/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>11+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1903502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1903501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>12+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1912502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1912501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>13+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1921502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1921501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">6/30/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>14+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1930502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1930501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>15+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1939502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1939501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">app</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>16+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1948502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1948501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">6/30/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>17+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1957502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1957501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">voucher</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/1/2026</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000;font-weight:bold">┃</span>18+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1966502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1966501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>19+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1975502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1975501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">6/30/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>20+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1984502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1984501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>21+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">1993502</span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#000000">1993501</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">48</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>22+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">8823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">8822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">7/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>23+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">17823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">17822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">voucher</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/2/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>24+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">26823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">26822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/2/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>25+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">35823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">35822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">7/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>26+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">44823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">44822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">card</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/2/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>27+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">53823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">53822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">4/2/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>28+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">62823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">62822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">app</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">10.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">7/1/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>29+<span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">71823</span><span style="background:#3a3a3a"> </span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">71822</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">cash</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">47.99</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">30.9</span><span style="background:#000000"> </span><span style="color:#ffffff;background:#000000">1/2/2026</span><span style="background:#000000"> </span><span style="color:#757575;background:#000000">│</span>30+<span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f">Sheet1</span><span style="background:#1f1f1f"> </span><span style="background:#40e0ff"> </span><span style="color:#000000;background:#40e0ff;font-weight:bold">▦</span><span style="background:#40e0ff"> </span><span style="color:#000000;background:#40e0ff;font-weight:bold">trips</span><span style="background:#40e0ff"> </span><span style="background:#1f1f1f"> </span><span style="color:#959595;background:#1f1f1f">+</span><span style="background:#1f1f1f"> </span><span style="color:#757575;background:#1f1f1f">│</span><span style="background:#1f1f1f"> </span><span style="color:#ffffff;background:#1f1f1f">untitled</span><span style="background:#1f1f1f"> </span><span style="color:#959595;background:#1f1f1f">modified</span><span style="background:#1f1f1f"> </span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">Ctrl+K</span><span style="background:#3a3a3a"> </span><span style="background:#1f1f1f"> </span><span style="color:#959595;background:#1f1f1f">search</span><span style="background:#1f1f1f"> </span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">Ctrl+/</span><span style="background:#3a3a3a"> </span><span style="background:#1f1f1f"> </span><span style="color:#959595;background:#1f1f1f">shortcuts</span><span style="background:#1f1f1f"> </span><span style="background:#3a3a3a"> </span><span style="color:#ffffff;background:#3a3a3a">F10</span><span style="background:#3a3a3a"> </span><span style="background:#1f1f1f"> </span><span style="color:#959595;background:#1f1f1f">menu</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">SOURCE</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C1867502</span><span style="background:var(--vt-palette-7)"> </span> 483+<span style="color:var(--vt-palette-0)">▦</span> <span style="font-weight:bold">trips.parquet</span> <span style="color:var(--vt-palette-0)">2,000,000</span> <span style="color:var(--vt-palette-0)">rows,</span> <span style="color:var(--vt-palette-0)">5</span> <span style="color:var(--vt-palette-0)">columns;</span> <span style="color:var(--vt-palette-0)">sorted</span> <span style="color:var(--vt-palette-0)">by</span> <span style="color:var(--vt-palette-0)">fare</span> <span style="color:var(--vt-palette-0)">Z</span> <span style="color:var(--vt-palette-0)">to</span> <span style="color:var(--vt-palette-0)">A</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">C</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">trip</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">payment</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">fare</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">miles</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-4);font-weight:bold;text-decoration:underline">day</span><span style="text-decoration:underline"> </span>6+<span style="color:var(--vt-palette-8)">────────────────────────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1867502</span><span style="background:var(--vt-palette-6)"> </span>1867501 cash <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">48</span><span style="background:var(--vt-palette-6)"> </span> 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1876502</span><span style="background:var(--vt-palette-7)"> </span>1876501 app 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1885502</span><span style="background:var(--vt-palette-7)"> </span>1885501 cash 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1894502</span><span style="background:var(--vt-palette-7)"> </span>1894501 voucher 48 10 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1903502</span><span style="background:var(--vt-palette-7)"> </span>1903501 card 48 30 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1912502</span><span style="background:var(--vt-palette-7)"> </span>1912501 card 48 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1921502</span><span style="background:var(--vt-palette-7)"> </span>1921501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1930502</span><span style="background:var(--vt-palette-7)"> </span>1930501 cash 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1939502</span><span style="background:var(--vt-palette-7)"> </span>1939501 app 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1948502</span><span style="background:var(--vt-palette-7)"> </span>1948501 cash 48 10 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1957502</span><span style="background:var(--vt-palette-7)"> </span>1957501 voucher 48 30 1/1/2026 <span style="font-weight:bold">┃</span>18+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1966502</span><span style="background:var(--vt-palette-7)"> </span>1966501 card 48 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>19+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1975502</span><span style="background:var(--vt-palette-7)"> </span>1975501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>20+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1984502</span><span style="background:var(--vt-palette-7)"> </span>1984501 card 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1993502</span><span style="background:var(--vt-palette-7)"> </span>1993501 cash 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8823</span><span style="background:var(--vt-palette-7)"> </span> 8822 cash 47.99 10.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17823</span><span style="background:var(--vt-palette-7)"> </span> 17822 voucher 47.99 30.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">26823</span><span style="background:var(--vt-palette-7)"> </span> 26822 card 47.99 10.9 4/2/2026 <span style="color:var(--vt-palette-8)">│</span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">35823</span><span style="background:var(--vt-palette-7)"> </span> 35822 card 47.99 30.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">44823</span><span style="background:var(--vt-palette-7)"> </span> 44822 card 47.99 10.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">53823</span><span style="background:var(--vt-palette-7)"> </span> 53822 cash 47.99 30.9 4/2/2026 <span style="color:var(--vt-palette-8)">│</span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">62823</span><span style="background:var(--vt-palette-7)"> </span> 62822 app 47.99 10.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">71823</span><span style="background:var(--vt-palette-7)"> </span> 71822 cash 47.99 30.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>30+ Sheet1 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">▦</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">trips</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-0)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">SOURCE</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C1867502</span><span style="background:var(--vt-palette-8)"> </span> 483+<span style="color:var(--vt-palette-8)">▦</span> <span style="font-weight:bold">trips.parquet</span> <span style="color:var(--vt-palette-8)">2,000,000</span> <span style="color:var(--vt-palette-8)">rows,</span> <span style="color:var(--vt-palette-8)">5</span> <span style="color:var(--vt-palette-8)">columns;</span> <span style="color:var(--vt-palette-8)">sorted</span> <span style="color:var(--vt-palette-8)">by</span> <span style="color:var(--vt-palette-8)">fare</span> <span style="color:var(--vt-palette-8)">Z</span> <span style="color:var(--vt-palette-8)">to</span> <span style="color:var(--vt-palette-8)">A</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">C</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">trip</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">payment</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">fare</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">miles</span><span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-6);font-weight:bold;text-decoration:underline">day</span><span style="text-decoration:underline"> </span>6+<span style="color:var(--vt-palette-8)">────────────────────────────────────────────────────────────────────────────────────────────────────</span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1867502</span><span style="background:var(--vt-palette-6)"> </span>1867501 cash <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">48</span><span style="background:var(--vt-palette-6)"> </span> 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1876502</span><span style="background:var(--vt-palette-8)"> </span>1876501 app 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1885502</span><span style="background:var(--vt-palette-8)"> </span>1885501 cash 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1894502</span><span style="background:var(--vt-palette-8)"> </span>1894501 voucher 48 10 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1903502</span><span style="background:var(--vt-palette-8)"> </span>1903501 card 48 30 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1912502</span><span style="background:var(--vt-palette-8)"> </span>1912501 card 48 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1921502</span><span style="background:var(--vt-palette-8)"> </span>1921501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1930502</span><span style="background:var(--vt-palette-8)"> </span>1930501 cash 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1939502</span><span style="background:var(--vt-palette-8)"> </span>1939501 app 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1948502</span><span style="background:var(--vt-palette-8)"> </span>1948501 cash 48 10 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1957502</span><span style="background:var(--vt-palette-8)"> </span>1957501 voucher 48 30 1/1/2026 <span style="font-weight:bold">┃</span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1966502</span><span style="background:var(--vt-palette-8)"> </span>1966501 card 48 10 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>19+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1975502</span><span style="background:var(--vt-palette-8)"> </span>1975501 card 48 30 6/30/2026 <span style="color:var(--vt-palette-8)">│</span>20+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1984502</span><span style="background:var(--vt-palette-8)"> </span>1984501 card 48 10 1/1/2026 <span style="color:var(--vt-palette-8)">│</span>21+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1993502</span><span style="background:var(--vt-palette-8)"> </span>1993501 cash 48 30 4/1/2026 <span style="color:var(--vt-palette-8)">│</span>22+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8823</span><span style="background:var(--vt-palette-8)"> </span> 8822 cash 47.99 10.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>23+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17823</span><span style="background:var(--vt-palette-8)"> </span> 17822 voucher 47.99 30.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>24+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">26823</span><span style="background:var(--vt-palette-8)"> </span> 26822 card 47.99 10.9 4/2/2026 <span style="color:var(--vt-palette-8)">│</span>25+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">35823</span><span style="background:var(--vt-palette-8)"> </span> 35822 card 47.99 30.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>26+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">44823</span><span style="background:var(--vt-palette-8)"> </span> 44822 card 47.99 10.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>27+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">53823</span><span style="background:var(--vt-palette-8)"> </span> 53822 cash 47.99 30.9 4/2/2026 <span style="color:var(--vt-palette-8)">│</span>28+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">62823</span><span style="background:var(--vt-palette-8)"> </span> 62822 app 47.99 10.9 7/1/2026 <span style="color:var(--vt-palette-8)">│</span>29+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">71823</span><span style="background:var(--vt-palette-8)"> </span> 71822 cash 47.99 30.9 1/2/2026 <span style="color:var(--vt-palette-8)">│</span>30+ Sheet1 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">▦</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">trips</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-8)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+K</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">search</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+/</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">shortcuts</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">menu</span></pre>\ No newline at end of file@@ -191,7 +191,7 @@ func overBudget(c StreamCall, book Book, budget int) string {
191191 if cells <= budget {192192 return ""193193 }194- return fmt.Sprintf("%s holds what it reads: %s cells of %s, more than max-cells (%s). SUM, COUNTIFS, XLOOKUP and the like read a source of any size",194+ return fmt.Sprintf("%s would hold %s cells of %s, past max-cells (%s): SUMIFS, XLOOKUP and the like stream them instead",195195 c.Fn, grouped(cells), biggest, grouped(budget))196196 }197197 @@ -86,8 +86,10 @@ const (
8686 8787 // available reports whether the command can run in m's current state.8888 func (c *command) available(m *Model) bool {89- if m.sheet.IsSource() && !sourceAvailable(c.id) {90- return false89+ if m.sheet.IsSource() {90+ if on, decided := sourceEnabled(m, c.id); decided {91+ return on92+ }9193 }9294 if m.sheet.IsNotebook() && (!notebookSafe(c.id) || gridTakes(c.id)) {9395 if g := m.gridIn(); g != nil {@@ -48,6 +48,7 @@ type Picker struct {
4848 field int // 0 is the search, 1 the condition's value4949 fields [2]string // the text of each field5050 shown []int // values matching the search, best first51+ condOnly bool // no values to tick, only the condition: OnlyCondition5152 overlay.List // over the rows: "Select all", then shown5253 }5354 @@ -76,6 +77,14 @@ func (p *Picker) Start() {
7677 p.search()7778 }7879 80+// OnlyCondition has the picker ask for the condition alone, with no81+// values to tick, for a column whose values are too many to list (a82+// linked source's). Call it after Start.83+func (p *Picker) OnlyCondition() {84+ p.condOnly = true85+ p.focus(1)86+}87+7988 // close closes the picker without applying it.8089 func (p *Picker) close() {8190 p.h.Close()@@ -211,7 +220,9 @@ func (p *Picker) Key(k tea.KeyPressMsg) tea.Cmd {
211220 case key == "enter":212221 p.apply()213222 case key == "tab" || key == "shift+tab":214- p.focus(1 - p.field)223+ if !p.condOnly {224+ p.focus(1 - p.field)225+ }215226 case p.field == 1 && (key == "up" || key == "down"):216227 if key == "up" {217228 p.cycle(-1)@@ -264,7 +275,7 @@ func (p *Picker) Mouse(e overlay.MouseEvent) tea.Cmd {
264275 case x == ansi.StringWidth(p.condChip())-1:265276 p.cycle(1)266277 }267- case e.Row == 3 && e.Kind == overlay.MousePress:278+ case e.Row == 3 && e.Kind == overlay.MousePress && !p.condOnly:268279 p.focus(0)269280 case e.Row < firstRow || i >= n || i >= p.Top+p.rows():270281 case e.Kind == overlay.MouseMotion:@@ -278,6 +289,9 @@ func (p *Picker) Mouse(e overlay.MouseEvent) tea.Cmd {
278289 279290 func (p *Picker) Status() (string, string) {280291 th := p.h.Theme()292+ if p.condOnly {293+ return "Rows must meet the condition", th.KeyHints("Up/Down", "condition", "Enter", "apply", "Esc", "cancel")294+ }281295 if p.field == 1 {282296 return "Rows must also meet the condition", th.KeyHints("Up/Down", "condition", "Tab", "values", "Enter", "apply", "Esc", "cancel")283297 }@@ -362,6 +376,9 @@ func (p *Picker) Layout() []overlay.Box {
362376 if search == "" {363377 input += th.Muted.Render("Search values")364378 }379+ if p.condOnly {380+ return []overlay.Box{{ID: ID, X: x, Y: y, Lines: th.Frame(inner, p.title, "", []string{theme.Cells(th.MenuBar, cond, inner)})}}381+ }365382 lines := []string{theme.Cells(th.MenuBar, cond, inner), theme.SepRow, theme.Cells(th.MenuBar, input, inner), theme.SepRow}366383 for r := range rows {367384 lines = append(lines, p.row(th, p.Top+r, inner))@@ -129,3 +129,29 @@ func TestAnswerInTheLocale(t *testing.T) {
129129 t.Fatalf("a bad condition: %v", err)130130 }131131 }132+133+// A picker of the condition alone draws no values, keeps Tab on the134+// condition, and applies the condition typed.135+func TestOnlyCondition(t *testing.T) {136+ h := newHost()137+ var got sheet.Criteria138+ p := New(h, "Filter B payment", 3, nil, sheet.Condition{}, func(cr sheet.Criteria) { got = cr })139+ p.Start()140+ p.OnlyCondition()141+ boxes := p.Layout()142+ if n := len(boxes[0].Lines); n != 3 {143+ t.Fatalf("%d lines: %q", n, boxes[0].Lines)144+ }145+ if strings.Contains(ansi.Strip(strings.Join(boxes[0].Lines, "\n")), "Search") {146+ t.Error("a search for values with none to search")147+ }148+ keys(p, tea.KeyPressMsg{Code: tea.KeyTab})149+ for range 7 { // None, Is empty, ... Text is exactly150+ keys(p, down)151+ }152+ text(p, "card")153+ keys(p, tea.KeyPressMsg{Code: tea.KeyEnter})154+ if got.Cond != (sheet.Condition{Op: sheet.CondExactly, Arg: "card"}) || len(got.Hidden) > 0 {155+ t.Errorf("applied %+v", got)156+ }157+}@@ -205,8 +205,7 @@ func (m *Model) formulaBar() string {
205205 return m.notebookToolbar(v)206206 }207207 if v := m.srcView(); v != nil && m.mode != modePrompt {208- name, text := m.sourceCell(v)209- return m.th.Header.Render(theme.PadRight(" "+ansi.Truncate(name, nameBoxW-1, "…"), nameBoxW)) + " " + text208+ return m.sourceBar(v)210209 }211210 name := m.cur.String()212211 if m.away() {@@ -91,8 +91,21 @@ func (m *Model) sourceCommand(c *command) (tea.Cmd, bool) {
9191 return nil, false9292 }9393 94-// sourceAvailable reports whether a command runs on a source's tab.95-func sourceAvailable(id string) bool { return notebookSafe(id) || sourceTakes[id] }94+// sourceEnabled says whether a command runs on a source's tab, when95+// the tab decides it: those that would change cells don't, and those96+// acting on the source do, whatever they say of a sheet.97+func sourceEnabled(m *Model, id string) (on, decided bool) {98+ switch {99+ case notebookSafe(id), id == "data.source_all", id == "data.source_reload":100+ return false, false101+ case !sourceTakes[id]:102+ return false, true103+ case id == "data.filter_remove":104+ info, _ := m.sheet.Source()105+ return info.Source.Order != nil && len(info.Source.Order.Filter) > 0, true106+ }107+ return true, true108+}96109 97110 // copyOrder is a copy of o to change, never nil.98111 func copyOrder(o *sheet.SourceOrder) *sheet.SourceOrder {@@ -124,7 +137,7 @@ func (m *Model) openSourceFilter(info sheet.SourceInfo, col int) {
124137 }125138 }126139 title := "Filter " + sheet.ColName(col) + " " + m.sourceCol(info, col)127- m.openValuesPicker(title, 0, nil, cond, func(cr sheet.Criteria) {140+ p := m.openValuesPicker(title, m.srcView().ColX(col), nil, cond, func(cr sheet.Criteria) {128141 o := copyOrder(info.Source.Order)129142 o.Filter = slices.DeleteFunc(o.Filter, func(f sheet.SourceFilter) bool { return f.Col == col })130143 if cr.Cond.Op != sheet.CondNone {@@ -132,6 +145,7 @@ func (m *Model) openSourceFilter(info sheet.SourceInfo, col int) {
132145 }133146 m.setSourceOrder(info, o)134147 })148+ p.OnlyCondition()135149 }136150 137151 // sourcePivot makes a pivot table over the whole source on a new sheet,@@ -6,6 +6,7 @@ import (
66 "strings"77 88 tea "charm.land/bubbletea/v2"9+ "github.com/charmbracelet/x/ansi"910 1011 "github.com/FelineStateMachine/012/internal/locale"1112 "github.com/FelineStateMachine/012/internal/sheet"@@ -106,8 +107,11 @@ func (m *Model) sourceLines(v *srcview.View) []string {
106107 func (m *Model) sourceCell(v *srcview.View) (string, string) {107108 num, cell, ok := v.Cell()108109 _, col := v.Active()109- if !ok {110- return sheet.ColName(col) + "…", ""110+ switch rows, known := (srcHost{m, m.sheet}).Rows(); {111+ case !ok && known && rows > 0:112+ return sheet.ColName(col) + "…", "" // its row is on its way113+ case !ok:114+ return "A1", ""111115 }112116 a := sheet.Addr{Col: col, Row: int(num) + 1}113117 name := a.String()@@ -126,6 +130,13 @@ func (m *Model) sourceCell(v *srcview.View) (string, string) {
126130 return name, sheet.FormatTextIn(cell.V, f, m.locale())127131 }128132 133+// sourceBar is the formula bar on a source's tab: the active cell's134+// name and value.135+func (m *Model) sourceBar(v *srcview.View) string {136+ name, text := m.sourceCell(v)137+ return m.th.Header.Render(theme.PadRight(" "+ansi.Truncate(name, nameBoxW-1, "…"), nameBoxW)) + " " + text138+}139+129140 // sourceContext is the context line on a source tab: what it is, how130141 // many rows it has, and how they're ordered.131142 func (m *Model) sourceContext() (string, string) {@@ -221,3 +221,16 @@ func (v *View) DragBar(y int) {
221221 lines := v.Lines()222222 v.ScrollBar(min(max(y-firstRow, 0), lines-1), lines)223223 }224+225+// ColX is the screen column column col starts at, from the view's226+// left edge: the row numbers' width when it isn't shown.227+func (v *View) ColX(col int) int {228+ x := v.gutter()229+ for _, c := range v.shown() {230+ if c == col {231+ return x232+ }233+ x += v.colWidth(c)234+ }235+ return v.gutter()236+}@@ -18,11 +18,9 @@ func (v *View) Key(k tea.KeyPressMsg) bool {
1818 case "right", "tab":1919 v.Move(0, 1)2020 case "pgup":21- v.Scroll(-page)22- v.Move(-page, 0)21+ v.page(-page)2322 case "pgdown":24- v.Scroll(page)25- v.Move(page, 0)23+ v.page(page)2624 case "home", "ctrl+left":2725 v.MoveTo(v.cur, 0)2826 case "end", "ctrl+right":@@ -40,3 +38,12 @@ func (v *View) Key(k tea.KeyPressMsg) bool {
4038 }4139 return true4240 }41+42+// page moves the window and the active cell d rows, as a sheet's Page43+// Up and Down do.44+func (v *View) page(d int64) {45+ v.top += d46+ v.cur += d47+ v.clamp()48+ v.follow()49+}@@ -206,7 +206,7 @@ func (v *View) fit() {
206206 for c, col := range cols {207207 widths[c] = max(len(sheet.ColName(c)), len([]rune(col.Name)))208208 }209- fitted := true209+ _, fitted := v.h.Rows() // fitted again once the rows are counted210210 for i := v.top; i < v.top+int64(v.Lines()) && i < v.rows(); i++ {211211 _, row, ok := v.h.Row(i)212212 if !ok {@@ -0,0 +1,159 @@
1+package srcview2+3+import (4+ "strconv"5+ "strings"6+ "testing"7+8+ tea "charm.land/bubbletea/v2"9+ "github.com/charmbracelet/x/ansi"10+11+ "github.com/FelineStateMachine/012/internal/locale"12+ "github.com/FelineStateMachine/012/internal/sheet"13+ "github.com/FelineStateMachine/012/internal/ui/theme"14+)15+16+// fakeHost is a source of n rows, row i holding i and "r<i>", whose17+// rows from lost on are on their way.18+type fakeHost struct {19+ th theme.Theme20+ n, lost int6421+ from, to int64 // what was last wanted22+ counted bool23+ wantCalled int24+}25+26+func newHost(n int64) *fakeHost {27+ return &fakeHost{th: theme.New(true), n: n, lost: n, counted: true}28+}29+30+func (h *fakeHost) Theme() *theme.Theme { return &h.th }31+func (h *fakeHost) Locale() *locale.Locale { return locale.Canonical }32+func (h *fakeHost) Columns() []Column { return []Column{{Name: "id"}, {Name: "name"}} }33+func (h *fakeHost) Rows() (int64, bool) { return h.n, h.counted }34+35+func (h *fakeHost) Row(i int64) (int64, []sheet.LiveCell, bool) {36+ if i >= h.lost || i >= h.n {37+ return 0, nil, false38+ }39+ return i, []sheet.LiveCell{{V: sheet.Value{Kind: sheet.Number, Num: float64(i)}},40+ {V: sheet.Value{Kind: sheet.Text, Str: "r" + strconv.FormatInt(i, 10)}}}, true41+}42+43+func (h *fakeHost) Want(from, to int64) { h.from, h.to, h.wantCalled = from, to, h.wantCalled+1 }44+45+func view(n int64, width, height int) (*View, *fakeHost) {46+ h := newHost(n)47+ v := New(h)48+ v.Resize(width, height)49+ return v, h50+}51+52+func key(s string) tea.KeyPressMsg {53+ switch s {54+ case "down":55+ return tea.KeyPressMsg{Code: tea.KeyDown}56+ case "pgdown":57+ return tea.KeyPressMsg{Code: tea.KeyPgDown}58+ case "ctrl+down":59+ return tea.KeyPressMsg{Code: tea.KeyDown, Mod: tea.ModCtrl}60+ case "ctrl+home":61+ return tea.KeyPressMsg{Code: tea.KeyHome, Mod: tea.ModCtrl}62+ case "end":63+ return tea.KeyPressMsg{Code: tea.KeyEnd}64+ }65+ return tea.KeyPressMsg{Code: []rune(s)[0], Text: s}66+}67+68+func TestDrawNumbersRowsAsTheTab(t *testing.T) {69+ v, h := view(10_000_000, 60, 13)70+ lines := v.Draw()71+ if len(lines) != 13 {72+ t.Fatalf("%d lines", len(lines))73+ }74+ if l := ansi.Strip(lines[namesLine]); !strings.Contains(l, "1 id") && !strings.Contains(l, "id") {75+ t.Errorf("header row %q", l)76+ }77+ if l := ansi.Strip(lines[firstRow]); !strings.HasPrefix(strings.TrimSpace(l), "2 ") || !strings.Contains(l, "r0") {78+ t.Errorf("first row %q", l)79+ }80+ if h.from > 0 || h.to < 10 {81+ t.Errorf("wanted %d to %d", h.from, h.to)82+ }83+ // The last row is the tab's row 10,000,001, and the thumb is at the84+ // bottom of the track.85+ v.Key(key("ctrl+down"))86+ lines = v.Draw()87+ last := ansi.Strip(lines[len(lines)-1])88+ if !strings.HasPrefix(strings.TrimSpace(last), "10000001 ") || !strings.HasSuffix(last, "┃") {89+ t.Errorf("last row %q", last)90+ }91+ if first := ansi.Strip(lines[firstRow]); !strings.HasSuffix(first, "│") {92+ t.Errorf("the track at the top %q", first)93+ }94+}95+96+func TestRowsOnTheirWay(t *testing.T) {97+ v, h := view(100, 60, 10)98+ h.lost = 399+ lines := v.Draw()100+ if l := ansi.Strip(lines[firstRow+3]); !strings.Contains(l, "…") {101+ t.Errorf("a row on its way %q", l)102+ }103+ if _, _, ok := v.Cell(); !ok {104+ t.Error("the first row is here")105+ }106+ h.counted = false107+ v.Refit()108+ v.Draw()109+ if v.fitted {110+ t.Error("fitted before the rows were counted")111+ }112+}113+114+func TestKeysAndScroll(t *testing.T) {115+ v, _ := view(1000, 60, 13)116+ v.Draw()117+ v.Key(key("down"))118+ if row, _ := v.Active(); row != 1 {119+ t.Errorf("down: row %d", row)120+ }121+ v.Key(key("pgdown"))122+ if row, _ := v.Active(); row != int64(v.Lines()) || v.Top() != int64(v.Lines()-1) {123+ t.Errorf("page down: row %d top %d", row, v.Top())124+ }125+ v.Key(key("end"))126+ if _, col := v.Active(); col != 1 {127+ t.Errorf("end: column %d", col)128+ }129+ v.Key(key("ctrl+home"))130+ if row, col := v.Active(); row != 0 || col != 0 || v.Top() != 0 {131+ t.Errorf("ctrl+home: %d %d top %d", row, col, v.Top())132+ }133+ if v.Key(key("x")) {134+ t.Error("a letter is the view's")135+ }136+ v.Scroll(500)137+ if row, _ := v.Active(); row < v.Top() || row >= v.Top()+int64(v.Lines()) {138+ t.Errorf("the active row %d left the window from %d", row, v.Top())139+ }140+}141+142+func TestMouse(t *testing.T) {143+ v, _ := view(1000, 60, 13)144+ v.Draw()145+ if hit := v.HitAt(59, firstRow+2); !hit.Bar {146+ t.Errorf("the scrollbar isn't hit: %+v", hit)147+ }148+ v.DragBar(firstRow + v.Lines() - 1)149+ if last := int64(1000 - v.Lines()); v.Top() != last {150+ t.Errorf("the thumb dragged to the bottom shows from %d, want %d", v.Top(), last)151+ }152+ x := v.ColX(1)153+ if hit := v.HitAt(x, firstRow); !hit.Cell || hit.Col != 1 || hit.Row != v.Top() {154+ t.Errorf("a click on column B: %+v", hit)155+ }156+ if hit := v.HitAt(x, namesLine); hit.Cell || hit.Bar {157+ t.Errorf("the header row is hit: %+v", hit)158+ }159+}