From 6478bd1e6e851e3c9bfe58640dfb03ffb64f09f8 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Sat, 12 Sep 2026 20:05:15 -0700 Subject: [PATCH] feat: write equations through the page model; give new identities n 1 Math::paragraph builds the linear text and per-run object data from a Math tree (Latin letters as mathematical italics, one run per object control, the equation editor's Cambria Math italic style with the math flags and language), and a new equation pass in the page writer rewrites a changed equation paragraph the way OneNote stores one: the text, one style object per distinct span format, run boundaries, the text-run data array naming each run's inline object, and the language marker and flags every native equation text object carries. tools/native_math.py types expressions through the equation editor with AutoHotkey during a capture; corpus/math-edit/native-editor adds subscripts, a sub-superscript, parentheses, an integral and a sum to the MathML oracle, and the mapping now covers them (n-ary operators take limits as scripts for integrals and above/below otherwise; object arguments render in rows). The oracle tools treat equation runs like hidden ones, since native XML exports them as MathML rather than text. Gating the ten-equation candidate found OneNote 2010 silently dropping an outline element in roughly one build of five: deterministic per file, structurally indistinguishable from the ones that rendered, and never seen before because earlier rows added few paragraphs. OneNote never stores an object as {guid},0, and with page::text::new_id giving n 1 every one of eighteen builds and the written candidate rendered; corpus/math-edit/ native-drop keeps the dropped build, the cold read and a relocation experiment. The transaction writer also keeps native files' 1 KiB reservation after a transaction-log fragment that ends the file. corpus/math-edit/written is the cold read of all ten expressions with a screenshot; tools/test_math_edit.py checks it against the expected MathML. Assisted-by: claude-fable-5.1 --- corpus/math-edit/README.md | 35 +++ corpus/math-edit/native-drop/README.md | 23 ++ .../dropped/candidate/Open Notebook.onetoc2 | Bin 0 -> 1596 bytes .../native-drop/dropped/candidate/four.one | Bin 0 -> 14456 bytes .../native-drop/dropped/cold/page-000.xml | 3 + .../relocated/candidate/Open Notebook.onetoc2 | Bin 0 -> 1596 bytes .../native-drop/relocated/candidate/four.one | Bin 0 -> 14512 bytes .../native-drop/relocated/cold/commands.jsonl | 3 + .../native-drop/relocated/cold/machine.json | 1 + .../cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 3748 bytes .../relocated/cold/notebook/four.one | Bin 0 -> 14512 bytes .../relocated/cold/read/environment.json | 7 + .../relocated/cold/read/hierarchy.xml | 2 + .../relocated/cold/read/page-000.xml | 3 + .../relocated/cold/read/payloads.json | 3 + .../native-drop/relocated/cold/run.json | 18 ++ .../relocated/cold/scripts/cold.ps1 | 27 ++ .../relocated/cold/scripts/read.ps1 | 142 ++++++++++ .../native-drop/relocated/cold/source.json | 14 + .../native-drop/relocated/cold/teardown.json | 1 + .../before-read/environment.json | 7 + .../native-editor/before-read/hierarchy.xml | 2 + .../native-editor/before-read/page-000.xml | 3 + .../native-editor/before-read/payloads.json | 3 + corpus/math-edit/native-editor/commands.jsonl | 6 + corpus/math-edit/native-editor/equations.ahk | 68 +++++ corpus/math-edit/native-editor/equations.json | 13 + corpus/math-edit/native-editor/equations.png | Bin 0 -> 38707 bytes corpus/math-edit/native-editor/machine.json | 1 + .../notebook/Open Notebook.onetoc2 | Bin 0 -> 3764 bytes .../native-editor/notebook/links.one | Bin 0 -> 19184 bytes .../native-editor/read/environment.json | 7 + .../native-editor/read/hierarchy.xml | 2 + .../math-edit/native-editor/read/page-000.xml | 3 + .../native-editor/read/payloads.json | 3 + corpus/math-edit/native-editor/run.json | 18 ++ .../math-edit/native-editor/scripts/cold.ps1 | 27 ++ .../math-edit/native-editor/scripts/read.ps1 | 142 ++++++++++ corpus/math-edit/native-editor/source.json | 14 + corpus/math-edit/native-editor/teardown.json | 1 + .../written/candidate/Open Notebook.onetoc2 | Bin 0 -> 1596 bytes .../written/candidate/expected-mathml.json | 12 + corpus/math-edit/written/candidate/math.one | Bin 0 -> 15424 bytes corpus/math-edit/written/cold/commands.jsonl | 3 + corpus/math-edit/written/cold/machine.json | 1 + .../cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 3748 bytes .../cold/notebook/expected-mathml.json | 12 + .../math-edit/written/cold/notebook/math.one | Bin 0 -> 16920 bytes .../written/cold/read/environment.json | 7 + .../math-edit/written/cold/read/hierarchy.xml | 2 + .../cold/read/page-000.navigation.json | 13 + .../math-edit/written/cold/read/page-000.png | Bin 0 -> 39901 bytes .../math-edit/written/cold/read/page-000.xml | 3 + .../math-edit/written/cold/read/payloads.json | 3 + corpus/math-edit/written/cold/run.json | 18 ++ .../math-edit/written/cold/scripts/cold.ps1 | 27 ++ .../math-edit/written/cold/scripts/read.ps1 | 142 ++++++++++ corpus/math-edit/written/cold/source.json | 20 ++ corpus/math-edit/written/cold/teardown.json | 1 + crates/notebook/README.md | 2 +- crates/onestore/README.md | 2 +- crates/onestore/src/page/math.rs | 132 +++++++++- crates/onestore/src/page/text.rs | 4 +- crates/onestore/src/page/write.rs | 164 +++++++++++- crates/onestore/src/write.rs | 11 + crates/onestore/tests/page_math.rs | 249 +++++++++++++++++- tools/native_format.py | 3 +- tools/native_math.py | 70 +++++ tools/test_math_edit.py | 37 +++ tools/verify-document.py | 7 +- 70 files changed, 1519 insertions(+), 28 deletions(-) create mode 100644 corpus/math-edit/README.md create mode 100644 corpus/math-edit/native-drop/README.md create mode 100644 corpus/math-edit/native-drop/dropped/candidate/Open Notebook.onetoc2 create mode 100644 corpus/math-edit/native-drop/dropped/candidate/four.one create mode 100644 corpus/math-edit/native-drop/dropped/cold/page-000.xml create mode 100644 corpus/math-edit/native-drop/relocated/candidate/Open Notebook.onetoc2 create mode 100644 corpus/math-edit/native-drop/relocated/candidate/four.one create mode 100644 corpus/math-edit/native-drop/relocated/cold/commands.jsonl create mode 100644 corpus/math-edit/native-drop/relocated/cold/machine.json create mode 100644 corpus/math-edit/native-drop/relocated/cold/notebook/Open Notebook.onetoc2 create mode 100644 corpus/math-edit/native-drop/relocated/cold/notebook/four.one create mode 100644 corpus/math-edit/native-drop/relocated/cold/read/environment.json create mode 100644 corpus/math-edit/native-drop/relocated/cold/read/hierarchy.xml create mode 100644 corpus/math-edit/native-drop/relocated/cold/read/page-000.xml create mode 100644 corpus/math-edit/native-drop/relocated/cold/read/payloads.json create mode 100644 corpus/math-edit/native-drop/relocated/cold/run.json create mode 100644 corpus/math-edit/native-drop/relocated/cold/scripts/cold.ps1 create mode 100644 corpus/math-edit/native-drop/relocated/cold/scripts/read.ps1 create mode 100644 corpus/math-edit/native-drop/relocated/cold/source.json create mode 100644 corpus/math-edit/native-drop/relocated/cold/teardown.json create mode 100644 corpus/math-edit/native-editor/before-read/environment.json create mode 100644 corpus/math-edit/native-editor/before-read/hierarchy.xml create mode 100644 corpus/math-edit/native-editor/before-read/page-000.xml create mode 100644 corpus/math-edit/native-editor/before-read/payloads.json create mode 100644 corpus/math-edit/native-editor/commands.jsonl create mode 100644 corpus/math-edit/native-editor/equations.ahk create mode 100644 corpus/math-edit/native-editor/equations.json create mode 100644 corpus/math-edit/native-editor/equations.png create mode 100644 corpus/math-edit/native-editor/machine.json create mode 100644 corpus/math-edit/native-editor/notebook/Open Notebook.onetoc2 create mode 100644 corpus/math-edit/native-editor/notebook/links.one create mode 100644 corpus/math-edit/native-editor/read/environment.json create mode 100644 corpus/math-edit/native-editor/read/hierarchy.xml create mode 100644 corpus/math-edit/native-editor/read/page-000.xml create mode 100644 corpus/math-edit/native-editor/read/payloads.json create mode 100644 corpus/math-edit/native-editor/run.json create mode 100644 corpus/math-edit/native-editor/scripts/cold.ps1 create mode 100644 corpus/math-edit/native-editor/scripts/read.ps1 create mode 100644 corpus/math-edit/native-editor/source.json create mode 100644 corpus/math-edit/native-editor/teardown.json create mode 100644 corpus/math-edit/written/candidate/Open Notebook.onetoc2 create mode 100644 corpus/math-edit/written/candidate/expected-mathml.json create mode 100644 corpus/math-edit/written/candidate/math.one create mode 100644 corpus/math-edit/written/cold/commands.jsonl create mode 100644 corpus/math-edit/written/cold/machine.json create mode 100644 corpus/math-edit/written/cold/notebook/Open Notebook.onetoc2 create mode 100644 corpus/math-edit/written/cold/notebook/expected-mathml.json create mode 100644 corpus/math-edit/written/cold/notebook/math.one create mode 100644 corpus/math-edit/written/cold/read/environment.json create mode 100644 corpus/math-edit/written/cold/read/hierarchy.xml create mode 100644 corpus/math-edit/written/cold/read/page-000.navigation.json create mode 100644 corpus/math-edit/written/cold/read/page-000.png create mode 100644 corpus/math-edit/written/cold/read/page-000.xml create mode 100644 corpus/math-edit/written/cold/read/payloads.json create mode 100644 corpus/math-edit/written/cold/run.json create mode 100644 corpus/math-edit/written/cold/scripts/cold.ps1 create mode 100644 corpus/math-edit/written/cold/scripts/read.ps1 create mode 100644 corpus/math-edit/written/cold/source.json create mode 100644 corpus/math-edit/written/cold/teardown.json create mode 100644 tools/native_math.py create mode 100644 tools/test_math_edit.py diff --git a/corpus/math-edit/README.md b/corpus/math-edit/README.md new file mode 100644 index 0000000000000000000000000000000000000000..41c825e97f632849b7de0c268b6da349d45c3a74 --- /dev/null +++ b/corpus/math-edit/README.md @@ -0,0 +1,35 @@ +# Native equation fixtures for the math model + +`native-editor/` is OneNote 2010 typing five expressions through its equation +editor (Alt+=) on the Rust-authored link page, driven by +`tools/native_math.py` (`equations.ahk` is the AutoHotkey session, +`equations.png` the desktop afterwards): `a_1+b_2`, `x_i^2`, `(a+b)`, +`\int_0^1 x dx` and `\sum_(i=1)^n i`; `\sqrt(x+1)` did not build up and +left an empty paragraph. `before-read/` is the COM read before typing, +`read/` the read afterwards with each expression exported as MathML, and +`notebook/` the section OneNote saved: the linear text with U+FDD0/FDEE/FDEF +object controls and the text-run data naming each object's kind (29 +subscript, 30 sub-superscript, 13 brackets, 21 n-ary with its operator +symbol). `crates/onestore/tests/page_math.rs` renders every expression from +the stored section and compares it with the exported MathML byte for byte; +together with `corpus/m6/native-math-01` (superscripts, a fraction, inline +Greek) that covers the kinds `onestore::page::Math` claims. + +`written/candidate` is the page writer's output for +`equations_are_written_and_read_back`: on a fresh section, every native +equation of both fixtures copied as a new paragraph, then two expressions +built from `Math` trees (`x^2+1` and a fraction with a superscript in its +denominator) through `Math::paragraph`. The writer stores each as OneNote +does: the linear text, one run per span with a Cambria Math italic style +carrying the math flags and the math language, the text-run data array +naming each run's object, and the math language marker on the text object. +`written/cold` is the OneNote 2010 read of that section: its exported MathML +equals `expected-mathml.json` (the native fixtures' exports plus the two +built expressions) and `page-000.png` shows the equations rendered. +`tools/test_math_edit.py` checks both without a VM. + +Regenerate the editor fixture with `tools/native_math.py +corpus/link-edit/candidate OUTPUT` and the written one with +`ONESTORE_MATH_EXPORT` set while running the test, then +`tools/native_runner.py OUTPUT COLD --expected-pages 1 --collect-notebook +--screenshots`. diff --git a/corpus/math-edit/native-drop/README.md b/corpus/math-edit/native-drop/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ade70c8333c4197469b064ba2f7a46a2ef90d85e --- /dev/null +++ b/corpus/math-edit/native-drop/README.md @@ -0,0 +1,23 @@ +# OneNote 2010 drops outline elements written with `{guid},0` identities + +`dropped/candidate/four.one` is one of six identical-content builds of the +ten-equation page (`equations_are_written_and_read_back`); only this build +came back from OneNote 2010 with an empty outline element (`dropped/cold`: +the fifth equation `x_i^2` has no content, alignment or style). The object +bytes, identity tables, run data, styles, revision manifest and transaction +log are identical in shape to the builds that rendered, the drop is +deterministic for a given file, and across thirty builds written with the +model's `{random guid},0` identities seven lost one element each, always an +outline element, at varying positions. OneNote never stores an object as +`{guid},0` (its own objects are `{page guid},n` with `n` from 1); after +`page::text::new_id` moved to `n` 1, eighteen builds and the written +candidate (`../written`) rendered every paragraph. + +`relocated/candidate` is the dropped build with only that element's 56-byte +data chunk copied to the end of the file and the declaration retargeted; it +rendered (`relocated/cold`), so the loss also depends on where the data +sits, which is consistent with the identity being mishandled in a +position-keyed structure rather than being rejected outright. The +transaction writer additionally keeps native files' 1 KiB reservation after +a transaction-log fragment that ends the file, so no object data abuts the +log. diff --git a/corpus/math-edit/native-drop/dropped/candidate/Open Notebook.onetoc2 b/corpus/math-edit/native-drop/dropped/candidate/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..5194ada2c6b37c251317e1f42863c8b3e04af2bb GIT binary patch literal 1596 zcmZ3e|KIuM`!b(-j|5(YE0x6yJZat+ey-D@Ez@Z8LaXqD3~0dq?koZ6iC;aJUJ#%7 z_Qbjy(m;7+3{(Ce2taH`m;jW9iK7X_xho4_Rlqqwh5#Fcrvs!mutL}g5DHG(K-Itm zrev&{ouhNkzeQ-r_0&gGe#6{w)q?xk+Ww!;TP3SBKRU4QgQ*{-M?+u)hd=`h!xUKt znVm8WBH2KCACMLR21jzA%v#G|Q(fnoTv}Z`Z<+)s7YPAz8bdxqDMJy19+1vsNCk?3 z@-$GkfeT15GJKO^P=Vz*28JVFzJJ|V6}ChWs15`~3K$v;tc4Y|;xG8F@a5Vmc|Nrs zrds+1LjzBU!^^PT=}!AAzdv_*d+jz%4x$^Agvcw3Ff=fzBmfB@KsO#F4pP?DSo38g z+bZ{EACIfr3Y_H85MXG~t6=D0U;*i3VDJE9h!;RSkPeWn2UJ!9BnuV?$$)UA0np1( zwhYiLa5%uqH}74>O@~Dfb;JA*3ONwq0XhcVfgr;K92h1fK&=9s4ip2K1p**_=;jH7 w1c88K0#F~cTnqs6v6;<+!%m3lsOE#>3FIk|dzpY3WDkf2xpCRH`YFhI0MD$*!2kdN literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-drop/dropped/candidate/four.one b/corpus/math-edit/native-drop/dropped/candidate/four.one new file mode 100644 index 0000000000000000000000000000000000000000..428899c1b6802ee675a9153b221ac4bf51a7ecf4 GIT binary patch literal 14456 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 M$RwcqjWC-256kqPkpKVy literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-drop/dropped/cold/page-000.xml b/corpus/math-edit/native-drop/dropped/cold/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..ef7f8c5011c96b5d2211b9ba8ad535bfb8db6979 --- /dev/null +++ b/corpus/math-edit/native-drop/dropped/cold/page-000.xml @@ -0,0 +1,3 @@ + +x2+y2=z2]]>a+bc+d]]>Inline ]]>a1+b2]]>a+b]]>∫01x dx ]]>∑i=1ni ]]>x2+1]]>a+bc2]]> diff --git a/corpus/math-edit/native-drop/relocated/candidate/Open Notebook.onetoc2 b/corpus/math-edit/native-drop/relocated/candidate/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..5194ada2c6b37c251317e1f42863c8b3e04af2bb GIT binary patch literal 1596 zcmZ3e|KIuM`!b(-j|5(YE0x6yJZat+ey-D@Ez@Z8LaXqD3~0dq?koZ6iC;aJUJ#%7 z_Qbjy(m;7+3{(Ce2taH`m;jW9iK7X_xho4_Rlqqwh5#Fcrvs!mutL}g5DHG(K-Itm zrev&{ouhNkzeQ-r_0&gGe#6{w)q?xk+Ww!;TP3SBKRU4QgQ*{-M?+u)hd=`h!xUKt znVm8WBH2KCACMLR21jzA%v#G|Q(fnoTv}Z`Z<+)s7YPAz8bdxqDMJy19+1vsNCk?3 z@-$GkfeT15GJKO^P=Vz*28JVFzJJ|V6}ChWs15`~3K$v;tc4Y|;xG8F@a5Vmc|Nrs zrds+1LjzBU!^^PT=}!AAzdv_*d+jz%4x$^Agvcw3Ff=fzBmfB@KsO#F4pP?DSo38g z+bZ{EACIfr3Y_H85MXG~t6=D0U;*i3VDJE9h!;RSkPeWn2UJ!9BnuV?$$)UA0np1( zwhYiLa5%uqH}74>O@~Dfb;JA*3ONwq0XhcVfgr;K92h1fK&=9s4ip2K1p**_=;jH7 w1c88K0#F~cTnqs6v6;<+!%m3lsOE#>3FIk|dzpY3WDkf2xpCRH`YFhI0MD$*!2kdN literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-drop/relocated/candidate/four.one b/corpus/math-edit/native-drop/relocated/candidate/four.one new file mode 100644 index 0000000000000000000000000000000000000000..7433711135f00e498c90317f32aa6b1d601588fd GIT binary patch literal 14512 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 O643od7)_6RF8>ckL#9Lk literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-drop/relocated/cold/commands.jsonl b/corpus/math-edit/native-drop/relocated/cold/commands.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..69850c424cb1b2a1e5df73c83205d4b07edb1240 --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/commands.jsonl @@ -0,0 +1,3 @@ +{"command": "powershell -NoProfile -Command \"Expand-Archive -LiteralPath C:\\one-tests\\transfer.zip -DestinationPath C:\\one-tests\\runs\\capture\\notebook\"", "exit": 0, "stdout": "", "stderr": "", "error": null} +{"command": "powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\\one-tests\\read-current.ps1 -Root C:\\one-tests\\runs\\capture -CloneHost ONE-M6-18994D02 -ExpectedPages 1", "exit": 0, "stdout": "Read 1 sections and 1 pages.\r\n", "stderr": "", "error": null} +{"command": "powershell -NoProfile -Command \"Compress-Archive -Force -Path C:\\one-tests\\runs\\capture\\* -DestinationPath C:\\one-tests\\captured.zip\"", "exit": 0, "stdout": "", "stderr": "", "error": null} diff --git a/corpus/math-edit/native-drop/relocated/cold/machine.json b/corpus/math-edit/native-drop/relocated/cold/machine.json new file mode 100644 index 0000000000000000000000000000000000000000..d6aae3c8817206d58cebf3ef9ec46f97e6712199 --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/machine.json @@ -0,0 +1 @@ +{"name": "m6-18994d02", "hostname": "ONE-M6-18994D02"} diff --git a/corpus/math-edit/native-drop/relocated/cold/notebook/Open Notebook.onetoc2 b/corpus/math-edit/native-drop/relocated/cold/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..3a97cd8d0846f19172188a18bd577ce39548178b GIT binary patch literal 3748 zcmZ3e|KIuM`!b(-j|5(YE0x6yJZat+ey-D@Ez@Z8LaXqD3~0dq?koZ6iC;aJUJ#%7 z_Qbjy(m;7+3{(Ce2taHmm;jW9iK7X_xho4_Rlqqwh5#Fcrvs!mutL}gKni3I2!KSE z@PSAKFe=*~$^H1PUxS{PUdnOl^~_MIs}|hP*7pB&-YQw8`O$%WA3_Iq))vi${4k7N z#i;0L2n_iUXkcNOBFiANQ-(n#8%Xa1(gHwFCHKj!wfr^Jb)Lzk)y4CsNiYJ%gn&4W zA)ld?p@=~bNar!60!2Xi5GdQg1tb_5zR57CfYd_3kuTrBZmbGhA_(P+6fiUxSPLs^ z#b5AU;mfsC@_cGNOtth2h6bJxhnHcw)1CHLet+)r_S$Wj9Lzj)8X~VK!qC8=k^m%t z0Nr?yI7nGnW6hV1Y^&UteLSveD{zuWLx7<{uY#e2fd!`v0FaN(Y!)1LLQF?B9~4g@Pl4PED!W1UfM}2# zmu;(`vIHav0zkI{#lZmp3N$8gyo1sXNcEO^_rQu68nCA=t(V&m3eK(fo#0vVFTT?9 zG{|(^X$uyHAh&^3O224mC=}X$vXJ$TSLYfD^Dd=_6G7tG($0aZz#w(!yNn=t1_niu z22eU_XaI5FKMJ!bKd0)}bt3w`jOB$Hss=zwAOLv)#D-{LV9*d~Xy^gznPDWh+M4yG z`@Bgmj#h4)gh2AT0S!Gdz-Z@0N;r-d4LvqMF%~YMNvtg?3_ZvJ4YGluMw8)}4A59G rXOtKXfzc3vh5&L_ft7ind@l;bpbV!u_d^C$=_oZC0;3@?0zv=)i+?Tc literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-drop/relocated/cold/notebook/four.one b/corpus/math-edit/native-drop/relocated/cold/notebook/four.one new file mode 100644 index 0000000000000000000000000000000000000000..4cfd0b96d10b7d5ed5f848c747a1874d9f58c821 GIT binary patch literal 14512 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 + diff --git a/corpus/math-edit/native-drop/relocated/cold/read/page-000.xml b/corpus/math-edit/native-drop/relocated/cold/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..3685701532575c53a067a560d91fb8621a89816a --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/read/page-000.xml @@ -0,0 +1,3 @@ + +x2+y2=z2]]>a+bc+d]]>Inline ]]>a1+b2]]>xi2]]>a+b]]>∫01x dx ]]>∑i=1ni ]]>x2+1]]>a+bc2]]> diff --git a/corpus/math-edit/native-drop/relocated/cold/read/payloads.json b/corpus/math-edit/native-drop/relocated/cold/read/payloads.json new file mode 100644 index 0000000000000000000000000000000000000000..1ce91a413d6fff4d58765187b76756f0e97ae843 --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/read/payloads.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/corpus/math-edit/native-drop/relocated/cold/run.json b/corpus/math-edit/native-drop/relocated/cold/run.json new file mode 100644 index 0000000000000000000000000000000000000000..f098e0941df5abfd77ce061acfce6d721e895887 --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/private/tmp/m4/reloc", + "expected_pages": 1, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/math-edit/native-drop/relocated/cold/scripts/cold.ps1 b/corpus/math-edit/native-drop/relocated/cold/scripts/cold.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a0b99e7aeb86f4dc10032537800501a52ad65b4f --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/scripts/cold.ps1 @@ -0,0 +1,27 @@ +param([Parameter(Mandatory=$true)][string]$Root, [string]$CloneHost = '') +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +if (Get-Process ONENOTE -ErrorAction SilentlyContinue) { throw 'Close OneNote before resetting its test cache.' } +$key = 'HKCU:\Software\Microsoft\Office\14.0\OneNote' +if ($CloneHost) { + if ($CloneHost -notmatch '^ONE-[A-Z0-9-]+$' -or [Environment]::MachineName -ne $CloneHost) { + throw 'The disposable clone hostname does not match this machine.' + } + New-Item "$key\Options\Paths" -Force | Out-Null + New-ItemProperty "$key\Options\Paths" -Name UnfiledNotesSection -PropertyType ExpandString -Value 'C:\one-tests\Loose.one' -Force | Out-Null +} elseif ((Get-ItemProperty "$key\Options\Paths").UnfiledNotesSection -ne 'C:\one-tests\Loose.one' -or + -not (Test-Path 'C:\one-tests\profile-original-cache')) { + throw 'Park the personal OneNote profile before resetting the test cache.' +} +$cache = Join-Path $env:LOCALAPPDATA 'Microsoft\OneNote\14.0' +$parked = Join-Path 'C:\one-tests\caches' ([IO.Path]::GetFileName($root)) +if (Test-Path $parked) { throw 'Choose a new run; its parked cache already exists.' } +New-Item -ItemType Directory -Path 'C:\one-tests\caches' -Force | Out-Null +if (Test-Path $cache) { Move-Item -LiteralPath $cache -Destination $parked } +if (Test-Path "$key\OpenNotebooks") { Remove-Item "$key\OpenNotebooks" -Recurse } +New-Item "$key\OpenNotebooks" | Out-Null +New-ItemProperty "$key\OpenNotebooks" -Name '1' -PropertyType String -Value "$root\notebook" | Out-Null diff --git a/corpus/math-edit/native-drop/relocated/cold/scripts/read.ps1 b/corpus/math-edit/native-drop/relocated/cold/scripts/read.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..476094ab1e0c47077988a6461db2080cf208642b --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/scripts/read.ps1 @@ -0,0 +1,142 @@ +param( + [Parameter(Mandatory=$true)][string]$Root, + [int]$ExpectedPages = -1, + [switch]$UseCurrentCache, + [switch]$Pdf, + [switch]$KeepOpen, + [string]$CloneHost = '' +) +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +$notebook = Join-Path $root 'notebook' +$output = Join-Path $root 'read' +if (Test-Path $output) { throw 'Choose a new read destination.' } +if ($UseCurrentCache) { + if ((Get-ItemProperty 'HKCU:\Software\Microsoft\Office\14.0\OneNote\Options\Paths').UnfiledNotesSection -ne 'C:\one-tests\Loose.one') { + throw 'Park the personal OneNote profile before reading test notebooks.' + } +} else { + & "$PSScriptRoot\cold-current.ps1" -Root $root -CloneHost $CloneHost +} +New-Item -ItemType Directory -Path $output | Out-Null +$app = New-Object -ComObject OneNote.Application +$notebookId = '' +$failure = $null +try { + $app.OpenHierarchy($notebook, '', [ref]$notebookId, 0) + $process = Get-Process ONENOTE + @{ hostname = [Environment]::MachineName; onenote = $process.MainModule.FileVersionInfo.FileVersion; + powershell = $PSVersionTable.PSVersion.ToString(); schema = 'xs2010'; cold = (-not $UseCurrentCache.IsPresent) } | + ConvertTo-Json | Set-Content (Join-Path $output 'environment.json') -Encoding UTF8 + $sections = @() + foreach ($file in @(Get-ChildItem $notebook -Recurse | Where-Object { $_.Extension -eq '.one' })) { + $id = '' + $app.OpenHierarchy($file.FullName, '', [ref]$id, 0) + $sections += $id + } + $deadline = [DateTime]::UtcNow.AddSeconds(300) + $previous = '' + $lastChange = '' + $stableSince = [DateTime]::UtcNow + $settled = $false + do { + $pages = @{} + foreach ($section in $sections) { + $hierarchy = '' + $app.GetHierarchy($section, 4, [ref]$hierarchy, 1) + [xml]$xml = $hierarchy + foreach ($node in $xml.SelectNodes('//*[@path]')) { + if (-not $node.GetAttribute('path').StartsWith("$notebook\", [StringComparison]::OrdinalIgnoreCase)) { + throw 'OneNote opened a section outside the copied notebook.' + } + } + foreach ($node in $xml.SelectNodes('//*[local-name()="Page"]')) { + $id = $node.GetAttribute('ID') + $content = '' + $app.GetPageContent($id, [ref]$content, 1, 1) + $pages[$id] = $content + } + } + $signature = [String]::Join('|', @($pages.Keys | Sort-Object | ForEach-Object { $_ + $pages[$_] })) + if ($signature -ne $previous) { + $lastChange = $previous + $previous = $signature + $stableSince = [DateTime]::UtcNow + } + if ((($ExpectedPages -ge 0 -and $pages.Count -eq $ExpectedPages) -or + ($ExpectedPages -lt 0 -and $pages.Count -gt 0)) -and + ([DateTime]::UtcNow - $stableSince).TotalSeconds -ge 2) { $settled = $true; break } + Start-Sleep -Milliseconds 250 + } while ([DateTime]::UtcNow -lt $deadline) + if (-not $settled -or ($ExpectedPages -ge 0 -and $pages.Count -ne $ExpectedPages) -or ($ExpectedPages -lt 0 -and $pages.Count -eq 0)) { + [IO.File]::WriteAllText((Join-Path $output 'previous-signature.txt'), $lastChange, [Text.Encoding]::UTF8) + $index = 0 + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('unsettled-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + $index++ + } + $hierarchy = '' + $app.GetHierarchy($notebookId, 4, [ref]$hierarchy, 1) + [IO.File]::WriteAllText((Join-Path $output 'unsettled-hierarchy.xml'), $hierarchy, [Text.Encoding]::UTF8) + throw "Expected $ExpectedPages stable pages; OneNote returned $($pages.Count), settled=$settled." + } + $index = 0 + $payloads = @() + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('page-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + if ($Pdf) { + $pdfPath = Join-Path $output ('page-{0:d3}.pdf' -f $index) + $app.NavigateTo($id, '', $false) + $app.Publish($id, $pdfPath, 3, '') + if (-not (Test-Path $pdfPath) -or (Get-Item $pdfPath).Length -eq 0) { throw 'OneNote did not publish the page PDF.' } + } + [xml]$page = $pages[$id] + foreach ($file in $page.SelectNodes('//*[local-name()="InsertedFile" or local-name()="MediaFile"]')) { + $bytes = [IO.File]::ReadAllBytes($file.GetAttribute('pathCache')) + $hash = [BitConverter]::ToString([Security.Cryptography.SHA256]::Create().ComputeHash($bytes)).Replace('-', '').ToLowerInvariant() + [IO.File]::WriteAllBytes((Join-Path $output ($hash + '.attachment')), $bytes) + $payloads += @{ page = $id; object = $file.ParentNode.GetAttribute('objectID'); + kind = $file.LocalName; name = $file.GetAttribute('preferredName'); + sha256 = $hash; bytes = $bytes.Length } + } + $index++ + } + [IO.File]::WriteAllText((Join-Path $output 'payloads.json'), (ConvertTo-Json -InputObject $payloads -Depth 4), [Text.Encoding]::UTF8) + $all = '' + $app.GetHierarchy($notebookId, 4, [ref]$all, 1) + [xml]$finalTree = $all + $finalIds = @($finalTree.SelectNodes('//*[local-name()="Page"]') | ForEach-Object { $_.GetAttribute('ID') } | Sort-Object -Unique) + if ($finalIds.Count -ne $pages.Count -or @($finalIds | Where-Object { -not $pages.ContainsKey($_) }).Count -ne 0) { + throw 'The notebook hierarchy changed while collecting page evidence; repeat the cold read.' + } + [IO.File]::WriteAllText((Join-Path $output 'hierarchy.xml'), $all, [Text.Encoding]::UTF8) + Write-Output "Read $($sections.Count) sections and $($pages.Count) pages." +} catch { + $failure = $_ + [IO.File]::WriteAllText((Join-Path $output 'failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + throw +} finally { + try { + try { + if ($notebookId -and $CloneHost) { $app.SyncHierarchy($notebookId) } + if ($notebookId -and -not $KeepOpen -and (-not $UseCurrentCache -or $CloneHost)) { + $app.CloseNotebook($notebookId, $false) + } + } catch { + if ($null -eq $failure) { throw } + [IO.File]::WriteAllText((Join-Path $output 'cleanup-failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + } + } finally { + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) + } + $app = $null + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + if (-not $UseCurrentCache -and -not $CloneHost) { + Get-Process ONENOTE -ErrorAction SilentlyContinue | Wait-Process -Timeout 10 + } +} diff --git a/corpus/math-edit/native-drop/relocated/cold/source.json b/corpus/math-edit/native-drop/relocated/cold/source.json new file mode 100644 index 0000000000000000000000000000000000000000..53bb12f720a4d76d1e02b4b87f0835318dc0cdbf --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/source.json @@ -0,0 +1,14 @@ +[ + { + "path": "Open Notebook.onetoc2", + "bytes": 1596, + "sha256": "3362ba38101c160a3089a7c35655071f3fefa99af400ee1b93ee9d2a6606382f", + "mtime_ns": 1789266331848783406 + }, + { + "path": "four.one", + "bytes": 14512, + "sha256": "70b21f337a82ff1ac8c6241a7c683f83282a863bdcf2aff70b36be6b9bf279ab", + "mtime_ns": 1789266316867267531 + } +] diff --git a/corpus/math-edit/native-drop/relocated/cold/teardown.json b/corpus/math-edit/native-drop/relocated/cold/teardown.json new file mode 100644 index 0000000000000000000000000000000000000000..05a47793de40f322e745c4c4183727e3590ecf70 --- /dev/null +++ b/corpus/math-edit/native-drop/relocated/cold/teardown.json @@ -0,0 +1 @@ +{"absent": true} diff --git a/corpus/math-edit/native-editor/before-read/environment.json b/corpus/math-edit/native-editor/before-read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..c6f3c040d906633ca3626a4d737023c43ed6bfbf --- /dev/null +++ b/corpus/math-edit/native-editor/before-read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-E6AF28E4", + "cold": true, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/math-edit/native-editor/before-read/hierarchy.xml b/corpus/math-edit/native-editor/before-read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..40f536eca488a69460fc9b98b4ef4b0a534a64c0 --- /dev/null +++ b/corpus/math-edit/native-editor/before-read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/math-edit/native-editor/before-read/page-000.xml b/corpus/math-edit/native-editor/before-read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..671946b6afd0514d154ce0bd177794f7eb93b4e7 --- /dev/null +++ b/corpus/math-edit/native-editor/before-read/page-000.xml @@ -0,0 +1,3 @@ + +the Rust site]]> diff --git a/corpus/math-edit/native-editor/before-read/payloads.json b/corpus/math-edit/native-editor/before-read/payloads.json new file mode 100644 index 0000000000000000000000000000000000000000..1ce91a413d6fff4d58765187b76756f0e97ae843 --- /dev/null +++ b/corpus/math-edit/native-editor/before-read/payloads.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/corpus/math-edit/native-editor/commands.jsonl b/corpus/math-edit/native-editor/commands.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..ccb54ae43192f687407fa302f88a4e7138e4f1d3 --- /dev/null +++ b/corpus/math-edit/native-editor/commands.jsonl @@ -0,0 +1,6 @@ +{"command": "powershell -NoProfile -Command \"Expand-Archive -LiteralPath C:\\one-tests\\transfer.zip -DestinationPath C:\\one-tests\\runs\\capture\\notebook\"", "exit": 0, "stdout": "", "stderr": "", "error": null} +{"command": "powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\\one-tests\\read-current.ps1 -Root C:\\one-tests\\runs\\capture -CloneHost ONE-M6-E6AF28E4 -ExpectedPages 1 -KeepOpen", "exit": 0, "stdout": "Read 1 sections and 1 pages.\r\n", "stderr": "", "error": null} +{"command": "powershell -NoProfile -Command \"Compress-Archive -Force -Path C:\\one-tests\\runs\\capture\\* -DestinationPath C:\\one-tests\\captured.zip\"", "exit": 0, "stdout": "", "stderr": "", "error": null} +{"command": "powershell -NoProfile -Command \"Rename-Item C:\\one-tests\\runs\\capture\\read before-read\"", "exit": 0, "stdout": "", "stderr": "", "error": null} +{"command": "powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\\one-tests\\read-current.ps1 -Root C:\\one-tests\\runs\\capture -CloneHost ONE-M6-E6AF28E4 -UseCurrentCache -ExpectedPages -1", "exit": 0, "stdout": "Read 1 sections and 1 pages.\r\n", "stderr": "", "error": null} +{"command": "powershell -NoProfile -Command \"Compress-Archive -Force -Path C:\\one-tests\\runs\\capture\\* -DestinationPath C:\\one-tests\\captured.zip\"", "exit": 0, "stdout": "", "stderr": "", "error": null} diff --git a/corpus/math-edit/native-editor/equations.ahk b/corpus/math-edit/native-editor/equations.ahk new file mode 100644 index 0000000000000000000000000000000000000000..92df26f2f1e8caea89cb1c05977e74189f736940 --- /dev/null +++ b/corpus/math-edit/native-editor/equations.ahk @@ -0,0 +1,68 @@ +ComObject("OneNote.Application").NavigateTo("{1163B9C4-333A-052E-26AB-AA3B02622A56}{1}{B0}", "", false) +WinWait("ahk_exe ONENOTE.EXE", , 30) +WinActivate("ahk_exe ONENOTE.EXE") +WinWaitActive("ahk_exe ONENOTE.EXE", , 30) +WinMaximize("ahk_exe ONENOTE.EXE") +Sleep(3000) +CoordMode("Mouse", "Screen") +Click(300, 140) +Sleep(500) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(500) +Send("!=") +Sleep(600) +SendText("a_1+b_2") +Send(" ") +Sleep(600) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(600) +Send("!=") +Sleep(600) +SendText("\sqrt(x+1)") +Send(" ") +Sleep(600) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(600) +Send("!=") +Sleep(600) +SendText("x_i^2") +Send(" ") +Sleep(600) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(600) +Send("!=") +Sleep(600) +SendText("(a+b)") +Send(" ") +Sleep(600) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(600) +Send("!=") +Sleep(600) +SendText("\int_0^1 x dx") +Send(" ") +Sleep(600) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(600) +Send("!=") +Sleep(600) +SendText("\sum_(i=1)^n i") +Send(" ") +Sleep(600) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(600) +Sleep(2000) diff --git a/corpus/math-edit/native-editor/equations.json b/corpus/math-edit/native-editor/equations.json new file mode 100644 index 0000000000000000000000000000000000000000..83fb4df3362bb2ac7e9fa657fe6db76614b54e31 --- /dev/null +++ b/corpus/math-edit/native-editor/equations.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 800, + "h": 600, + "error": null, + "win": { + "title": "Read about Rust the Rust site - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/math-edit/native-editor/equations.png b/corpus/math-edit/native-editor/equations.png new file mode 100644 index 0000000000000000000000000000000000000000..59b1d11bcc35c962edee976754ef848d6c51c989 GIT binary patch literal 38707 zcmaI72{_bW^gmwqtt27YLWr@HT|%~G4`J*RA=$~kOq1+ek&!)QiNTP4ovbnTeV3iF zjD2VR@A`iF)%W*%p8q^OPv(8^``&ZUd7ale=iWP^Pc@XTkliA?bm`I+Oo9hIp}9fBb?FlPL|H-hnP>8P9r0_%W!UG?u?as{p9+tP(}RtviDEWO)$$ic z9|K;5UrjDkS3MZbwjYb(P@VfBWPvVueB-57iNc5XPws_~c3!^Ia);sbmfX}1MH-#)`^@nw-=IMtuTm)~G0o>8r>F(YCj|H|i60ifaOr23Q8to%*GlAUf2(8crZFkIEkF=F$m!lrRE%+c+2U?C@fv+ z$wY5q5}Wauw72u=itu5su%&?Wwe<3$xtHPWx7pa{Hf*#l(1g#YvuovXJE39&eg*rO z0;3A=#&27=gq#gFI|uukUVp8J7+bZar6p^oP96b%$2|M$QE#ogw9PW#WV-nIxydW^ z#iMD;{P%1oTIKC0G%NfPN0tihBay`<+#baf+EkBie0=%^y|o8jZq=2TAV{U&uH?lT zNQIeOxcRuz4aIesW>h@3$u6Tj*NL(@%oVr_sOqX-?5!k$O7|Nf)zy=)7gZ)A!&BGv zRjaGXeX3o6f8N#Id#_X0tGssLPkBMGeP|C|&C9Sio>E?FMyHB?k$plr-Bm8eYi`^Q7%fV@xJ}=l2Ix51fO-h!=tR!!Lm)lq{+DHVW)|3R0p@a(F2SocfDcl z@IWEYFqru}+r1*f1HoI~?|%H2s&)D3BYne3S3}|rkS*pGwX~=S6}Vu`k!fqwBfJ{J zzh-bAK&j_1<2DqX?N%vZ+_{;&HPleI|6^v_*VlI>ZWE+b7>@dcGg}HZ5uO;A%}{`~o059h1EXi`w9}`^mxF`J*4nPYIBwgcG(l$Ed^cBH zjiN;tIEBSwW(8*1%^uGFsk%e3ppl8SF+2bO)wY4o$ZZ!4X2_PaMJ2kT8?Mut7+dI( z1THtG*5yD7`j^fct_=a|oKloRH=JK|II4k9_B|-oMqR$1^><>`HT)r+Aj+uK`o1ZD zqz)+p=UQ0*?PW-dD!kmySeU7_I-7qDqPI|eyd&YoXr%N!RY;_v2v5>?V? zBf+lY5)@7A7Po)qlO`>45j&fy2f(st^raG{?2r{X?q^5@Ukne}@${WWUfPXn^?Tpo zz_)rTN=jeLm$}jKp;Q!Zr@5IE@9^Du;3UHy%9NdwZ>Di;y)UpMT*S&pYta5#Ohw%O zvBW_eC9643a`cACD!BKOTnU6;w`}~qr zqPFX_>+H+Z(`D!xjh8F%7&M3+4cUlmPUu4{<1gi z!-I>-;F*N;t%-s9o#7yTJ=4M(!PyCF+&+1xBE+kFIHYUo0?URp6!wc1-k{qTNoSV~EVin*D%Rr9pSxS7KtF99J&97xBu3FLIkic|VfRcGHB%Fdd{{mEbqt>r4(6 z77=o@?vS^b@!yJU)FkKfmDx|j`V_2L>8}Qn6&sAt~Gw!n2H9sJqLS&_Xm zLR!A&_$LXT=k30e#xmB*k-gygMnFU|5ED}gq3P=bhp--&Ty|5 zy?k2x%?JG+nBBl3^Ti)G4l$Y?fM(YyhDD^Jd84j<`d-rin({w~n%8PN?a*pc*_Qso z&tmYtw(O3l&xUG8lxy@|5P5mnp&{;owvEzGhS$po1~w?=lUTU@9kicG??EZ0So(bp z&E}2Apdg;;tb}{nQr}@@HyGbi|KZ(K>rNaglUl@#houJ<3v9&9t3G|1hpOzx$%}Ja zM1275eDrpWU9TAPyo%)=jPszrk)+}mtj3CK@zH9e^cPQ4Q^t3BG%g~^bNPNUf$kPH z?!rx$-}7G?nhf1Q4~e+BOK}$z?ggynJY@i7v)_f40fAoylCoOmvf#Z#*QR!{y|A`1 zQV}(Fk;7V4_Zpku&~Pds;J>=hpzoM!1P6&G?Xy^~Nmi5@i8XJtb9IEH%ii@ffYu=J z`p5cq?mI_c!9<286JG?dC&JJpqmCTE$D{R!LSR~@l|>4`8{q;`t0$jLWQa#)PG+8b ztf1eBR5230=E*g%<;dcRBiA8q-3X}It}9~D%qvv<{xfw_%237@A`W3$!hlE!u-)Z8o$ql$}T07jRol_y0caXFeu`<`p2LH*7s zb&AT&dJIx=BW>ELHKziaGsnv_GPm*8T30!iKcY@3zqRlu7T9lOu=1C>t=J0h?id#u z>zlZx6i$O%;~IB!dcpzTQrZtB<$A1PZ&uCMAN2u0U+M)BdWYo1kvu4+S&#s3yv0|wc~#VCohknugg*}FsQUI^*p`rKnvC>kuaDtMNm0*vJ#Wl z`1OjKFCry^yST1nT{}8H^X)Ib*LlZKyT4g)-|S=ggPS+Xs*drbWN+k2qrJtbct6B@ z-%r0mHh3Rv^`nYcaX z*{?H81(3Z3w7YO8+buztU1vOvK8e9g^@EZDmkaL@9$GlS(u+U}X`b+1aD#cXrSDdF zbGoHypkOc_?ummT*kc>1A??44$tCB(&(@{KoV+Q9-WSfeyq*F^e0{H=-c&wLIPC z7-x*=fkdA4o6Y#TV20rNEi7>5@B){Fy%B#-3A7$&&JoTS#mNu7!_&O&qsK#Vf5- zIyK(QuHfmcV6u-fuz34y`k5%r$;GNRlxCU(?uUI`zs6p6r6tMt(5ELYc75hz%Xecf zv%*e@SwZBr&!U3sN6F0Kuha||eE3{~jNhRP&v%#Bl)4jhC^^S}%6p8AP$Z=dUE6%w z8rRCs0Phk|#YHsNc4@8Av93eBPyOg-cxNCKYwAU)dre~eEA589#PX?`Lmm<`$wVy)xz?Ca2papF|!a98;NtfhmKpju9#&)dxLx~Z7j`-ju!rI0!^#P9H`U$G&fxdIm!Drdn&X3 z_i$hu*ihv{gMjhb%#y%K(JtME*)Hu_eAVtnbd@V^H(3HI!?huk)pZeV^X;NyObFMs zo&Xh7{Sucws`#zGxGHO3PTt~MJ?9{grkjJqMY}~#l&|}Y3hn>rNW<%%}9PyinJm`tN6s7|CvJTIPM0rzSRD+Uoc3+`o7K;r$=)8ngic zJtb?fo-GSQ63}F4Onb3pAn^ao9nAb`R6N)LK`@*+3!;^J;MmPB#HY^iK+1k4qEsn6 zpM0RDaXsCiB~{us7t<8>E!h9_xsJgW)aIZmXd@UyoRH3_qjhXusYBj^YThE@1+=dA z(V9G8(GW;UeSktr%SIxTHa~kYLap6vrz|B_pHar>r|3oo!EhdyHx2hA*?>}=(rqbV zz)JcEHYd+=7fq?2wEeS`emt|}o?G>a_`GcKJ+~8io$PQC%CF>7Xq;msH8zG2EPtw@dx>J z$6ISQKn-(Qe4lp^n|(U@evX-^%hsqd6IVQQ9jD7ytAXwep6000L{om@iSBq?jaW6x zDg*!+!$+06P*e*nL(F)0E8NxEMXqx5aW^52%KcVv zj~3^7Qxyo`X=}g1VNbG4&&Q`+Gbs;_H``;eRM{F;`fg7!3qCqr;ccw3oHJtFy5cX) zF@Drs&}m%HX|qh6WeaPp_Bna%5Yx~U7pP5(^6u4qM%?Bz^tZp-X7oH{D)Mx(D|g&{ zl~q(&5;id)IJvRW;WAECR-C=`@M64sN(ukaf*Tfh@nequP(97p`V}%Z@T-TKN*%k% zzQ%@@bH7QfHa2nZVhWozxvgxe`KJ6Fq#d;W74vmm=#FLMd#N}nd+UqDor^lGdbRc3 zmm0t9X(^i+@sAnaYWA{>$5G1TtIq<0Scy1;=o}$T8Vv9=XW2^V1GMHch0e`7j-H^* zeVkBNs#s^RJ6l_QxjBSriBV(EGlNo)Px7E{$uIHfJ4mKl)`C`sp(DCjCnz{1SHkCe z|A(H4>tTVt&>*4LCn|$+qPB6)jT=eLiFtNHX9b^?5jXMBBl7-3D3z+Ux{A$FoxTBg zOws&>drytyO#XxBiml=IQ<(T^^(ryTIVmhC(k)sBIXI<*Rke3;q&R$*bCO77ntSd`DW#`q=nt6 zL1mASHf3sTviL>eN3qROlj#9>mrlv~&D47rsUNowHE!l;7>5?#l6;|GHEueOO}IB3 zB~>3<_*M!#wLkqul1shTLi^_@Ib7A?KmyHg_K8> zmp*3sBB~|!z9_FHe4QoKD|xQQkUSTSkWIGs9=}@$BpS3!^ESzK7++7@ihrfzzTX)C7Rt?h%UzMw0VfgJ8HR+lZ%VVx$?M+`t#C7mxo_O^wP2)&%g5f%9cbdItygtia ztY{69iWKHp!R^9Bzi&DoYI>BC1`_oy80GA5`5>KN+~ZFNg(Pg9Lw8ZQ@WVR&V^KXl zp8e1DvGjtCIGK)?Bx79Hz|EP{^De4SJ@?FsV>xay&qkS^}lT9>GkO_`AR;6?w0e5ns|+7DNM zs4XM2ecscsY_!{2<0$o$ocG)c(ZF3{t?qf4`mtSJ+nPcvN@#cb>i{-EblzbW7%Ox@ zT}yLWvP|^)@Ay``yh%?zqH1FSxuRC2a5FXIf#VJDbB@>O%QfsBCHiM**>3?_sfM_Q zygZme`%g0AXdRyhndBuOY}(;h0f!Tx_d#oKXp5pB=b*7#nOM>6JlYK(OA1FXv)bO&JG!&9HRQ=@m!vERvDL+=^ub36K+L(kdZWPP|`|CRTQ^k7(c zP`al58?&Jxq`nqk>(^3*|Go-uPFKQ6n!E@F=lfr35R|!bQ~66;4~(hdIN~ZJ0PVtI zaPeTA{_&@v7%sC3n>^445wG8-%HYtCijQjnHIxj}*|Wz!xaxzx#c-BnN$jrB67>1f z*{L;uC3N^Lu@#>$(Qkq2EEy|_?qK)>-$A3sA-f${d%TMj@x zue+wuJL|u(>q1oMh8PxbI!-T$Dp8YqwODOG|{}^?XqJ~y{KbfZ|PUF z)Ca5S&$cVKJ{YW;r3pb-I=Rgf1h>&&sadXTTsKQRTWl9%N#$hLX-Iys57No;v&0~Z z{E5y9iDMtPL?4bIj+bI6gZaV7KN{oAj4Cl};d)TN?L-M-(JiF8i5(9jrG^*X12!~6FLRT|g z1sllM!qV64-599>&u>P_hs3#&{!MfC2ul> zw|s56q~~Y<;bz3m7%+Fx;oSRTQm7vw`S!uyYuM=&O&bf;etD~+{ z*Q4E8$HZ$0b*tu_cumaTCy*q?EjqghYBzS`$TzXIvBG|D9 znB(vrPBuHD8+Oyh`#7E9ZTcaxVgCz*k=4;CIiLtps6Kre`UA17eKj=qdKlpcz1Gvh z2p(A3a$8cx6|`m{(S`JZ@X_cvvj^@WfYc z!lS8>YK;b3>fc5=f<1zXqm|}v%xNV*OE#oh82qj?dm=(F!wjkUTj)Kv?ksRRzqZZ zSHRu(Bs?W8YBFITZIX8W>d?AjJYjzg_|seeK&OThXVo)1vni2ryvNmO(c|l~=aI(f zw-n2MK{zCp*wK*_C%|-E@N`UnTg<09UHY`_DI+vTJW%|Dc#8N}@v@t!?`igQ0aQSh zce?(y?ss{i@@2>99apN9=R!q7aN4-fk(f{Pnbl0+%%!tg%LZ{I<2VAIii^Wo? zwUDNC1+LlkR8!jH=OC6c*?acqD&5so@9m%TU0N4`bd;$~S-Ci!yX6lH9`g8bUtGKq z|It2!)xUa#5Z}3+{#T9@E<)ChwuOI>7uf-NSog^svSV!CXB!y%`RJMu6@UIDI6Ahmf_<(Hrh0CY5L`_(3t{MJr zR>fO8$g0W7Q7x0auy{fbHt)5MuYQ$OeXY8Rd}adKJC3Rr@V)ihlLvl@X%R#BAH&va!M3Ci8=-1kku*9e+5S_rmI3_V0(EP6@ zUcG-88G*&oMX^-mAkCj#bDpl6DDM(+pp`%_b&CY4eAL-n%-34&+UywEbIfmzD=r(< zmz?Y~C*>U=YK^5|*`!hwdC0fC7`>xlV^i_m&D~wPhD{T}n~z@UQDfy780xz>0&G3 zH(s%`->`GoTq)q=qszCwC5D~Uv|wd>@clCiV_^rTKL2b;PCzI75%s{-YSJ(YCHV0B z&jiGZQaC$u&@Fv=1(Q(MBkB8U_+X$6M*bEKvS><0d0R|2i?!Arw~mStuLqkF=oxek zZM|B&@jSrP-YUIDx)&^YV3qdJsJG9#s_NKWM@MNgY{~}Mh6ujt8~U`W|Al|%RpTE! zbtb{aiqEE}D(nZWU#LkQ`P^O4x(D?%M%rcHgSmY_B5cZ-ElI+yf6o+=Nx9b~#KJYH zGA~|M##$7=YIE>z4K(mHvM6s=@!DyUdj%OUT7ow#i!3PTMS+xI{@KOndY9l5L1AQ& z!ShK}x$3)&LR04RB{bCE65_w22#ND93Oby;qoq+rCAu zWaNh5vlsBTiApcx$iR?K5P1ie!+qH&kM4$l$BxL_Ker2h-(@Odck?nf|dCcrP9+7xYT^ef_yS{@T#{+oiWuJbI2x zPG%h~r6d=f{A_bv28Oy)OHMS3ALk-Ss}ydg7kUGiG*kzNc5yo$y8^Z1mt^+XkSewM zP5B=Of~#1`*JwGvMi?$%8RO+%4RGZ!#RlW@>|=yiAHADDMLc7$JumO1y^m}?2ns46 z^;@1gvo zn6D+2Iq5@$uwhX3M9-gLSk-aS`$k$my28WVo$N!?*}z=~EkBP&1^d~qhPr&d2!B6> z4Z{b6jAGF~U_GHilWoFBw{8m);@R#UV(SU?dW#woiY67W@Xj22(}1ahmT@jvJhU&` zFIwi^+Y$QZSo11kP~#fy1V>{pJ#Ss%#mDXScP4XM9vjnhKN{p-8t6;86T;zo4Zc>l zF?oF~;J{5l=u`jxd~~+~|0n(Wqu?)eBi??JsT2F=F|%pK2Bw+9!v}R^shHOB@!{Mk zzg?znaqmv>_EATEk&%Or8T7l!)FZ&@I6HnOO-3{5$Tz&D-5V}wh%+(^_*ScMQySR` z+S>`akK9vcLg#yC>#Y@6w|62rU(%uH-${8=G_=sUP(we?u&uj75+3(vnKCk#xvU6* z+B&B_R$H@9PP*lD!YNY`~-RQ;h|q^@!uQ&Ob&%vzwm!>Qn&EEBFl)W?Um(I zN1kxj20RF(^-86Bn-GOaN7fMJEhnB|(k(8e1Gk&V>lfp_T-vQ_QwyhWf{ZXZ6}IHt z*KdHY@G)uU66*O6#cidkD|@@G8lVZo<0i82NHw(DK9oC1)K|C7Fr0Hl@OT7_Oqj3Q z7By^R8n|%BaU**o0ud)ou07G-OJmD?6-5R6B6_;&7L8`^ze1UGyWdX|A4eZt8Y18N zV8`#!*LLqyMf@qIgR{9O`r_Li1IVJT=~Zk3sd5p&1fZv?67P0ZWo3blGdnEa4Bw_Q zdAZ_)`mzo_1Cavyv={o%hJ7A(m4kH#3>VXjuTc>j;@RFN_3@~g`UExGh3`zfwUwE6 za5UL}N1#`8;}tB<$axG#>r?pAC$5zTR8)}ns&wzL2lvhMY-6A&w9V`SBQ`5KP*CVl zxHITD{=qggDaL3R?X z(?)0?U+i$(&$g$X@xB&{W!8*+iHNQk0Q>|04vf%Gb`JGG-@UzsDl^b3Efic7HT> zsVwY3TMnsM0Ki0dVC;(X^0aIbf|`-Q&6kjn@=9|PB6G7r3r_CRLf*_a_p*6gncnFW ztCs3)O!Z@RP5S_4KBNYX$Ag*LFx8CW^34mxXJqx4FT=DTo?ARqZVW;PH2QkMzt28C zIqgSKDaXD*fOPctXK)JFB(kLR!gKRjN{CZ@9)i1J^468PzASVr$4JV8k1S`q>5?CUt0U%Pp!KekQsj z3t#PDj|_&(hV*^Z^-=}pt9DGaSn4Wf#RYQE5OOS57tRUtA*1NrJIpn_J{O0Dy|U{Y z0UI5rwu7z}kplO+I3pc>@20SsD4;?jsP41JaJGZ>+00Ld;uzdXq(nM=<0e4;dHjC+ zOB^5>(@OL6x0Y*5d?u0}?U+(UkhQ>>)9_mwPRi6g2~73fcqJF3T~%8>Xl=fXX?t%x zkdG3l%}G&NY6*8Hx8y5yhI}C<(6hJ5_gpT_v;T^)q1E$D>c|g_v`h`su0Ym*$t$cZ zDa_5#1A|RssQ!e z9dx6aQuGz*pXrV0dA%w#06Dj^A2THe?~VtKRoUm!3Co~uhHfz2dHBhj34F|Sas=eU z7Ftl^!Rc#dVoK+A*DdcW7v*0j=iTQAIT~2HX&J=Pg0oBe{ToZVD}22R$Ck%9fnrUz z5ND!Ui+{^Jyfdc%5o9QrCGg%Qn6BX}cL9Q*zli547V#j12%f4}U-)3+^@>{N*3Sf@ zS=azz!2sh8K24v~0dG|hAKy0;-YN^u#yfq>O$t#jfHwhZBKJeUoPvvjtv!tf8ksm(8s3*XB3jD z@a%-E^eoe?z_NyhFm6de8LyRV2~RI3;Y|=G&@&l85x@=gEhP%)gqC;p97faC&1_ut z=a#wqph_f{F5TV^5o`8qvyF&sxdS&o;6Uot2}w`f1QTm>7KGdcZ_o(<6iySrOb1Wx z5qRLnuSCvEwUm}>EB!kA0}8m>xuS)?7MsajQ2fz0a5*udIR-7=1>y5@9u3(ZGlXoU z-7_BzQ4TgIL7ZijOun7_Rz=9wld6xeT6Ll5u$rp&v+!wTaFhoSNcZ6mPE2o8a;YC~$Y6xa~5NCW4A#m)EQtJX+Y;$ASp z2rpgg%_JH=kmsl=0Ua>s(_*8?b>;9>+2%5>A+HSky*pk3xCR3?kvm2D=;!=`p5h&cL;Lg7e>{k>gfM~83sk-jxp!xNSMUHY2q zDFUJU1kc(y~k?9(&Ul?tA(&q6#MUAU0IA}QVx!99zNtHjz|Ec(EPR)qV# z*GmQHJMSDsR!kGY(^(@QD001};;^%lEbZv^E{wC2HDy*{C z`Nf1WM?-nn{^EzD<=vu}vgNj`pbJ4ErMMvux%uyYRoQm5n-QU#c_fiT`F@HfQu~b{ zO{raTC;>dBLGj5inO}m5hlyMvWoBzsZj0{0I`Usj4AS*ff9KFmjri;j2{ zJeBZYP<^)~)KT~(pUZ!L?QUP|?@`1fb76}~_1c&`DG--Agm6(~OGI+xt;y&2Z{yjC z;Sa>Jx6UTT(!`8EM7)lzp%$Pzi1k&&zjW!%e8_e1NsBBMSYi`FosDvNBWO&&t{?k~ zK_KMj&Txh2D`JerEi!-#=~ATQp?d_s92+A04%IKc&+|-)5WYitwc>F313+E<@uES@T^*Ikv`gyteVsQdH>XcZ4sIKy`57y8)D>A`bMLXs65PNqJMYnL;BBTD=# zo~nCnspMqcepl*vkSX!-#i3HOYbbKT*MD}^)k{e;nf2G(a;(S~6#_7tv-?--D%*c^ zR0si#qsEUE;VF|1`^8xyB)`5_D^yyag`nDm8570L2MzhDfR;TbV3J?-6BKQA?>hx8 zu=*?4z$FtENt5$ud~&~KzrHwq;Kkt5+s@x}7hIJuKJR2NLjcEBkeC^#PcL+H$N@rB zO6A(DKQ!wv-HeS9sZrekiV{aEe?k9u*TItuSAh-{EN#0OJuH7Q;F#Q> zGnKW85mXT7z8J`L(H|Td;y7t|_GW@iUit2aYi0}-k01t{%!fZSnfOvsm{au2Y=A8` z!UGlq9@kV?^W=9-NUjN(*vd7NxEnj%1qsx9ZkuP|@(C-|S5$Su%wGg1_S_FEiD%Ma zmNUjFQn0cG#e7N^7GAL`eLc8`@vBD)u{D%TVtg;*`tV-xC49N9!Ek0G^@R5CBQ z{K!ZA1Ua!6S*W;sBJ_=2V+8h&FDZ6q-|7dsD_2V7ganMlx8SbmTMdJ*WL}B5zk|L$ z^Mvg=aKzP}G>HavBpTL=qc+>mO0x>&YcKqaTm7{`Jn4%vfr>4JOiWBBCMKb0MRbs@ zdFZ_UNh_|~@slpu4f)%wXA{KNoAUJ4CWsy9(G>H__#1usC^Gum#myz6^&yVN&jIhM z;-oe|C^Sx^3~7#iRPIob66x0G0C!l?VqZa&T zUQZ*boMx*naF~_D!1c0mdV#sR&V_B8a(A%|75cX5=W)5J*z|qoRZb6AG$Gc(4eht$ zw-glj+#G#YGI}qDWK=RB>+CC|84zsxk+Sy#+)nnsQeWy-ZT>aIrOEES2`O-ssiElI z&F?NW3)AcMZ$s*|&w}M4mr)xO4T?7jw;Nihr3fw^U&GA;34zmu%Q2=)F=>Ys@dWtl z48&B_hMJ=KX&6)B0pV~-{9Bn0zk8Dl8j#D)mjPm{5Hh+7ca&Z!##WF7(@ST==y~5v z+yr>R!HA58ix42|9=%E`w z_J=cGKCbwTT*Hd(Tv;vjhuS7RL64j^3GXEzfHmV$g0a0Q!HcmkpDuQ^UK5ET8ySBD zEn9jmWOt^1*+a?9lk*nqYipw_TWN(ONGkh%Vq$#GpzNUGx-V}~ct|>cJ4tzkNGW;e zXYxzay&0*&e!iyXx4`WQQWwR5*0-~+11hAt{d=nUWE9!C?F_BZqoAQ-=*Gh{7Im@p zjG^!grKU(paH?3PyYD}b!w?xKOShRppRrN#QxTO@e2bQN z)p+Bn9n4asiiQ>08N9mB(fIR@U_HU=ELTN@&Qq!=TETK8%yL}N4x-5LWfzEM>w&14 zsXH4&xAN8!Cq?!@;M*QY zZsERzbq9UHPlY*X4>a4 z@0#j*%LP=-W<7}gKNB%XA?vq?pp251Lwi{hrKsyT8DTLokH&W&y>^%FCo8q~hArc| zRpUtz($p?OmFfJv{Co7TllCXxmFK!9Kfb5^1hSeF?v4IfZ~2a)fQ_>M_?N@VLE0VEVEdhD ztXZ0rCIOt}>+mpq32xP=eR_y(@ZLy->&X@0_6|p37_!4ipb7U@INi@j2<0o(Jwg|M z@)wUQPW`YPMVs%wPg>lMWH%iTKd41SS%_P2EjGVrCpHTRzqfp2@45c0qYL(ar>G6O zer9zbdP$IxYXQ&fDXW1!{oeg+tUii2{{r9>-demsWX=ALEno*anxR}aLlsSs1>}5_ zu80)3;W1ANa1a?DIm(oTcWgru!e>yTa3=FqOCR_>9yuNV4XvT^adQepG;m!eBf}g( z5GB;+Ccr&LvHoG9qad$Sq_Ulky! zg9s47*IT_~Pjzr`whR?=-sm>!Ti`j>eEp(f{IwCN8UR=amOt3ZMj1-2DJUz4(t??3 z&?v)t-zsKsMaK;EWbu#$keA>;c_X=zdR-6s@oc-3B{FhLQHc_+R+XsnV!xW}U@re1 zbbKon_)-PwAB@;SXlQA}a{KY}GcpYM`0xPqPlBAlX@s5uQLX$I4q7dr8 zGD;^q3yZk*OU_UC;j5kr2_u(!l5&WLPnMLUaSLW7h|6tr*yEOB(npSe+;#=FzsqvI z>rsC^pl|xbEQ)A_{Ezff$c~3s1aKGUEPjU- zGK>d8CfE9_iDS%;@ICKpt<1-+Vsq=->j%iJWWRiYE{fiuD%&K9U0jx%NjtURA-8+`A1PaqA%N|k3y%iRjpB5f@**c|muDp|$;XLZ)~yOC+W8|azS3k#W%v*}Ek({3?n zo}^1N%aPH$?Q0LSUep`#WHW|cx0G!YPVM$+e;*!n?GF$p)=)fox#ydixH~tpbe}G{ z#p%((eZoPus`;1>sVi~Qk3H;l+)T(}G?cQ(7VF$1(3n_@N=Ydd01ptt?reJy+*k5` z4xzK$e}LI0fFqH$j|XXBmO`@a^GWJ1S*HQq*=D$KMsSe7b`sx$lX_i!KJ%l%zkx8c zu6+ucrJ)dm?aq6I-IGEl3JwUFTriaLin15ocK9di9!1-bD9J$I=>B}b`Uv|6L60C_ zuWpebQYS=^5gyO)hZ6qEPJY8TloYXh4BQWpat=a;QJu%10Zw)HR%RK7dMkeWzp$Y| zpeGwjf*4rd0o+X%K>u(5<-CpDAyaiVRwSTBLH^+53QTuG{2naM>>1qXsqd2SMR6?9 zd>g2he#dl0NSXJV5fFl;L{uRA`D{6ZD4rg^yArO`Efln<&wsl88fBr-CU<98-xJf3 z_eup+$3ZjHvY0w2=%Hn!%R)m;70h!zm?z(bMt^|@p4#QiB~uxA`sW4qtk|I9r95L0t{RdjTcg}S$M=6a!cc-DdT|w|xp8n>BWGLjC-z=(6<->4z{bw} zMJq?EyTFov{(-a~%+i5ZYR1rd|1FubO`wBHD^w_dflx>m!KbUA~$@V7Cs{0pgW%9*_L?)xTH-^3h+3?r*SM2U`IP z_=6}DJoLXgCXi9FA}`JT(HM~UbzkAt_l|k&Vx^POhWCHK1vFf}g2?WCVW!WW61Senje3H8n8}A zr_g&ZX~`dv{nf<$8z7IJfg`Q?4$2RNe*fx@65)SQ3)-;q$`=YL+LFC? zP2j(<1q`kH8nS=i)qGTHo%1ZxCWPhhvhIi@PaZ_x@WYYNw=mK+U-@gm>kQ!G3c2G8 z!So#oa6&>m6<0!rSPYh0bqExgZBOmIOGk12uO?!*P=a((hWhon+9h{g{)Mi+PzeA zR>(>P66arq*so*=@CfUv1?C$H#lCvFA5r}dC^AOL1v1u#$0XZ-pa%Rjn5Yv|&FP^o zADB~KIaxrYcNIn>=fq0L_N3-&E^kdg`<-VCD8U;az2kkH)VJ?nxhC_!w3Q(9a`14? zUq$qIvn&kQI!gL4GRTR}6Y;L#|I^nK!ePZ3ItE%{`1=ru1KbL@M??}mgaI^vS0)bZ zo-O?0binQY)Sv*h0$_X`g_^^sK|TKq!`5wB)`j777s10X0h#~Ue;!{o(Ch?1_|Izp zAC8!>MD0NPUq02O0{^`CkM0q`V?@oiBgx4yHTdV9e_C=;f*x_utgC61WLN*h3qV2* zGTw^^x1an8PQU!{2H2RG!0R7r0`S5$sR{pm;)d3;R=`Hv+gIbn-9_TWng|473PoO>)RPdqs5 zGO7m!n4|Yz&j&ZRRZ2ec{9k$sD{uwU1Vsj$k+Wup=k9{c_f{?nN8O2mJR5emtq=9u-h!~ z%MEI9uh`%D*{vZ}{bdZfgC@qS@By9iK0J=BP3nowOMU+sL>>=xV8$kFtQxU*oQ||0`}dKY{Eoo3Rlf{~-$TyU0%{ynoFsgclBacbon{ z*n{x$y?z-$&ua}mB?27Z0q1Je*4@+rFQ>5`ES60%3TL@^yZ~YxeoEM1)%}S`no>s{4f~Uz zqnEr+1b?-yyg~uTVXwC8sbhu#W#IicxH@n!$b4@~Bre`E?`Zv}^RI||#*CQ010MwvMWw&ql<ZFXH!*-mXG$N7et2ytfRCD_YkCaSssOAp{7X;O-jSt8jOBclY4I6I==? z+}$C#yF>6`!J#WT_x3q=dVbvQ>AC$pGyCVR+G{WQ^nJgzwiX%!1Q+~wN#bS&dp!YA zjGNbVZH9F(K2841B9;agD#-VCau8Q#>Z+@m(g?1*^zoazm^nZK zm0Z(T-7$$un;I{o$WOPwzv}IJaw8d4*!G!AC-7bin(U zK6pUv>9a5HZ>;Yx>M*ET{~}RXq`*oS>P(%=l0$KWz@&e+4|zMogFJ9q(r22M8}Z+@ z=5m(v%~$pHFcd{y%fd!*!KIGgRJAJHzhr6ugToK&f{FNFRO$bjsQ*7k8UOV!g`_+K z(6uAl`dg(;kg^cQQtmVWgw91H`lporKgenR*GK1kG+TOhb|xMVBh32GuIxB9FR!fF zueYWD41|*IjV0!S;9h@x!XHW!BBYHgx|*7vhtq}P7;wTwT3T9B(a{qB;CGCn38*00 zJ|x^eJUZg_e`)jR#YBxHLk)m)ad$u1-*0GWi0U#r!tY{+z<|_X#wLfYAPWdc*V_s& z3@5G?`3k(ex*{efme6H6M>Tj40rRkcc&jb0vTfSQ$;nxQz7KFvAzQPhs{Q@_OiWCq z^l}d{|JE&zylQ6sj#X$VmdT~1&$|Dxx1Y~4AQNBH(y^+mt)dLcxgG!H+@B8+Qo}qZ znh>DgZprWp`wRaGJ|TqgCimZ7K`2W|rUx17A8K{yFB1TvT^&gN_6G7}T=1W?@DF_s zajKB9LTLHF#P8qQi$Rh9%Ekb28odFUn!13qO1jctI5=s!qfFdxmyCZ#gNgEgdJIWr zZEs-BLW?Wg%8Hs+cj)PbGF2V^jeCdwKi#?it*a$rFo*FKH)r{h-rli!MP1E}bI|p= z50W}V>IiWDQce)L`7aTT&ybh})~va;0W__xwm%NRqny`Wce(!vgu(x}=KMdmfDjE? z3($n9M>&WYQV;NvQNUU7b?9Q|k8%ss{_jy~uF@V=E&~XlmaL(M55d$Rz#*i_))BaSj{9g>_TVOq`86>u=gTR?u=>VY9gUdmSA>QDB&hBQaomG;4 zl7#@cdpSXgBdbA)st1=fe}#hKf1$bmqh|d7ZodBCaWIe+)vSvV5`)mW<0q@_;^E}- zre*q`Knk({6Aojopr$MXy0##%rD^q)zH-PB7jl-&S{pBr%eSTdsU0=**?Pf*KXrMeu%{Z zzI<7xCNqx+HElI3v9`Ne#d33X&txrc>iH`%e~Yp5;ZpC&Hn7%P<|-CWosW( zKi0aD@>7#d?4?1-K`1ES5C~098(658tfjKH*0{{e9L=#{zmCJ8VLOI5&(&y|u0AtK z-!Z$qPDiGg<@%3j0wK>>1iF@+uf<_!ShL1i4$t|PKR(0~hwgD`nUV4V%EAFs2YX1d z5`Th_J{ZUlm0`-uTZ_vd=f{{0-A(0_@PJwXb+62pmR8h}Hlw|IVy^4xFfHTkI;(#f zB>`~MZSADPG^^vNW3GbkNQQm>QeJbQMXT;CptXTV)c9|Asv&WbT{0mkQ@61a)qd5= zuGJ)~qs+Qxa&h_HyiPmW*H){J$#+EMWksJE7q}WDtNuhPB7JE1M=t`^eHcC7zqLsdy;>yDE*47d2 z*HM4s+wf|(zs3o|EtqhPQ1>t_v=C|W&Sh4&w6@w;EP{UM*1PI8`_(=^j8z`%>cZpJ z=apxy@Y=h$MoU%eXwLZLx3<=3S^i_1A?(FctW)H#%X;S1TSR*|*T|5J8V_y1(u0wk z%JPNQRQnP7a=SLK{PNi~ik7mX@2AUSXK~}!3-&Gxjdjs2%MFiEe{~cQ;<6+md+Wy; zxcEN0@1=R@%jGcI*tFA*lopizzO2t=vP}~Qq<9fk>2zvp&QPW@w2e`=9c8ApEZ49l zO>{#Ha|8xNRUv0c_R_%|Z|`N|e_XTabg7+QapLV1WuHf_Dvt7_uPnnpotrG<(3mMK z*UfoAO{-i7%^X<`3Xa02s(D0>mh1HI@l@s|nL7*ec|q`8C@7>qbs)5X91qX^lwV!^ zp9kIjuMUv4j8j^U`It9As>J1eYaSPuvCBp1)qYoT?OW)73tImQ?dQUj_4O9Mt6FvP zb2Z}f@2AtT8AZ{jBl#)-a`Tf|u(4xvaS4dNv*ZZ^3q-Q6RiS4Qz70z=1BE)-{)+A&f&Wh?1~iOdg_qaUYP^&f)QIMDeQYz+ZwlG#u2fipByiBQ5!%g$VZIYm8PV2_i z7pDo|=GIkJB^YG9OWouS2#@99VMrraNufdaTUS5LjS7?c=w(ngtK@I9)fyGjA8<;{P5ElOx+ z&Q_cqYz37C!@KSWd=d8@Xg0V$|CD3*Tv8rSyT@?>?S@kyj0U^nYE-Z-qQPxLc59>R zQmyYo4r%Lem8Iu7g{~am0A26S_4?b)HGSxgwOS0Y|M>zUl)mrP8eqe(@q8ut@i+Mc zk;CRMt_@OXpU1T+dknG_ez*8{Gw1bX!FfYpz&#yhNHVc|3zoDr+4XQsCb0HCR zg^n}yQrLPJPe5Q+4g*`f2gX!;gCY@oX4%$%Fs!fgP4#dsO=DQ@#n&Lq)xVKxL>+cP z8goJ#bwinOjr-voIpQA69MB!TY9zb*wvf!xH0Oe#st@J7PbRm3K6lqj-=v-#>o_gw zN@`B{sT|s0QAtt~@$>r-!iX6(Ik9y4*GcQ^u}{*6q$CK}m|?BZu)CFXypPZYae^v* z-_m5PG2TwX{G{P@$51{bvdYM-#{RS@oNo+%p>{omgBsdk6E@jT)4jlW1GCKrxB9Ew zmVEU|1RIJ7W|Aa85}N(Zw?L>dI15JMBxoY^NuK~oICko9BG6+f7COS%utY?Ys{xXT z>;m7QVa6~mVuX|6h-fDH10_+|)xUMajNw_d31cG=u})?MN}h@>i$~yY@pS4?(vMCF zbfNE??`#`yZCaWg*cqX+)wpqhUFKO_Cs`Y2KGj^HMt(QP)k-w5Y(E2brTXMg?}CEH ztB=S$%I?KS2l*)x^#T-`?8kc=V7m}JtnqT5fxX_Zs8uC@MR+WIMf+$I*Sk4|y z&t1B-z9@eSOw8PO5JSKSZ>C2`0n|{?!$T(%u80BYpfP6M{2+CeI}Ow-B?OlL)TBTB z>U|e3WbzhRW-vABjCO-0JLMe9J6_-kn4;#z2dqu2t}N?nZfFHr)0bEcRe@jw-u%Kl z>1%WWaJoyG05($H1ut|^aSHI<(F!H#&{q;1^ePxY!>x+J-ztnnKAADNvzGi#g zGCFTsoPC9^U3}W0uwp~nu$;Uj!t^tHN1aVFw3t=cyTX!`fGYOWm52Zk6O#do3WzBi zm>`9Mlv@4f$K;5_Mo;9jsi{%1p+$a?ePNz;X^AaOl_kUxpB#}s1*D&o!i_F+^ste* zN-ghG7K``@;w`Kq>!7Fuv%df$hv>r14UK9>j980@=wa=<6&#REpq9Y$*%574N|-o^ zBEqyheHiy#jF0(9BupDxLa!X=vauykDfJAhN~zolaF#7Gak*7@Gu!P?+-z zAr3UWh$Chn6C*rafrQ>R?bZi85V&r8nsQO;g~@3;GLN>S2{^G?VDp+>*0tNyujE7T7XyIIDfy0MSEf{SxVf7tNMcQ{)&qv?d&sx{YSJz66w5)@< zumfFFKT{=KNl}T#?Q@vE=FNXtEju-dWPbQd3&F(%5dYCNdBG%W#CBkoBL!R!{ zSy*&hyAIBr03IfJ?r%j)k(dE+X-qK*OcAML@u|bniIP$>`R@yydJCO;sMy4)Sw*S0 z^GN|uzpp2Dhla0&T>^OIqh}e@GScNaRp^rqNz~MX3b7$%cIrc zkSEMb;u~|#@gvplfO%SzRPjbPE#K%T{T)`M_aL6tB$zgQOmzlN_WPf;c zK%R!3hNX%3Xo7WbYrA_6lNY3d@M4GbBdET*?{vCm-c6jfjdP-@6IXJsceQl7(bD+`xP5!W^5J0Dgw#qQ ztE~kPyKCS#1j>%}bRPey$IHzyk?3(PN=wP<*)l5AFRUg404ii^>x8B&h9yW@A^4&m zti-2L0LcvL8mTKF(@3f8$r*?|uP^oF^ZU92Xl1ib0)Vs~Yt8TI<{&@L3U7 z6PB6LneUOBqtjXAc%W7$s+`KOoBAuq0ZNh`juebY9eue+J1D8u=1;lTtAH1u5^Gdh zVdF_i;DV0zozD}?*`3u_-?dUfR6Wg|S7CbgdBm6nS{_i2;=i|`$mW%o86 zbY7&OD3am}5W}yDPaiFYYb52vv^*6p{WkV$89QuE-&!J-z%(@0+2Qt?rIB4J<)>sY zgG?8-W*1N70$t?byTBR2oL<4WF@%dAn%|*svXhFLR)DKplHm=VM>!VbKtG(0~5 z{D)GqxZMeTj85BU&mW*I^dB{<46C*jBB8yzy`MJ4GXs7YK=9TxW^Rd$Jv2!d!=C87- z$V5$_wctN5g-EX`7-CZzi!mWZ1yfMqAR+YxZC)+d0l&o40$CBj!NvZ5G!*8(B{{Pk%3?D4Q4FLmOy6j&)v06q zYi|+Ih%g%((mV-5hK?+DvNusMan7rXynplE{u0lc7WPhZ4sUUh(=AMhjeoYXe}#yD zg`bdKW0hoUwKNkN%?q-fdeGJ$UIdnhrj)cHDq|yc35c($j*mnZCd3G_*FkKHo06i; zjX+NbEAoTX)@Nmof*~Rm_8d6-43CoxD@^Typ9yrk8F_@)A_C6EA779JlTu6TOP9Th z)5`Khw1I&Q4KNhxLY3v;f>(vmPRf|;*Kf;|e{t+YY{&;!rQhjrT)&KFtxA( z6nQ8}Y$peGA@htI*Qj*|Eo^SySsInrNN`kmlo>49fPW*$j?$KO&)zbJzPv-JiaA4R zV1Wc#OkWHt7$XLTJEjXl(Un`PidsucusHRL*J**Z4W-1cvB6c@FhiQg+G~6$^S(6e z0bt-e9$OJYCO^wJGy{FrxslT>?&&2fRndWrSv zw;90wlc{H_&qXWfIQ)`~gwBXpW56vh>roBsey^S3auD9hL{Uq+~RiY!(?0G2k~1l z)am8SvMEh;FJ;iV#5sxkaV@3H=;3K(AE+Yk^TlD5giw!PehE*)>xq^}5&9Xu(2>v9 z)^Im}PF1I~N*Nx({XDW4Df3mlum-Mw+9NcPJJcwIpL3-E)?DNH&f5UMvk*64qVBHh zrL*gz&*5-SHb80B}1Jo!nrrQb`3K&>1Bctd{ALpYJ zrNv)~zrXaDEwF=J<>CbRSKe_B(s2&*R1fhHlLu7B54?R34&Isz`9&`(enWxz5rKdn zZ)0#XD603inw!cOViww;Q147KT1v`&8(gq0i#Re<)1reU^)SAnDS2J^3WKeb->d`P z!1{9_#Nm3xE(h;j*7{XCA0c_x)tA&Wwq-2`yNbr`5Y!{0;_C)ScSD0&y6UVfGSq{+ zg2m>KE80XcEkm28TXG7akn!O9WT27fM?`V6ryCX|p97$jA9L|=iY(0@>dY=AyGJn6 zZH>EDEWFp{!H_`B15x7QbLo|INi{NE$7gV|3)4C!a9+=WFj|;d7sL6S*6}?TnXNhJ zn_~Qo@sI4fhlTPmb`a>~{Dw5yyX6=kHS<+@2O)K+zl zO54W82vxlZYo$~qG5R^kA|gN0vN~GQA|LYxfhoAT`&D?W1)~fsmqX8ZJ${>;Rcnuo zcS`q)le%1$&koRs(A18*eXsi5WpG=O^c57WY5Szf=mXjI$^zLk<88WrIrOjs?-?L* zkJ4NG^935J>ZlUqtjzhe%sEHQyh4m`yslof7CwJ9NI65a8a{tggH?VAcN%| z+s7&THOr3)rFku5)=XW$fOzj+^XkF`xiW&728E0^>?IL@jkOqR<}9i2dyq-ln7tcu zHr3(DAq#J4eOsuD2I~b{Z5+d!kLQs+31)D|)eI=;aHF`PC8ype4 z;<^VEpj^i$4(H~~e`e@e3jC^D>FX1h^<%Kr;Il4}Fpr{jrew>M7;P%>*4c&TNR;(Z0F{+moCip<765!l z(XFLfBIZ%3TE@y3|Oa8+0(yb}duPjQ#C*;KYOMe->&uln>h^{Fj} z;HG<;u7|W0Eop}#3G}K$vPAB18k9r6PNiy3O8en&23OLlxw zH<~|C4ucHPAwFOeXH(q%xl|Bx&Q;LNgkE#=;~-!7(hY_)(Ma!I*-_uXryguVe63pl zm+bg+%0}e&m|@qq&s9qtFB7!8_y@D(hD#f*X1WeCLZ&G`zz-H{>Ui&%8Wol1%2j5y zMi`H3=B(LDH`!*brlHH4*wt;yWH@A+=_N|BN`VQWh|emtvR|r%M^dOqW^prO(eKEj zvI?BZi)I)+$Es*(3pi1Yq7M!7m6I7Job-ht+NMqjn8#C@G)N0^tYfid?PRrTv0r>Z z8$LtK>s1tAA&=NUkbHyAPV@|Q3;q-}@}}2CYT=7ui-B&-MF}aHzv!!Hd=!~G^7B&k1;O=4( z9K#wVDl>8Tmv}`L2{Qr{)6CudjPK54r9r0k<0J36@zevDdfY$4OM@vWG@@P;4cal) z+Wc+_J)VKk>Ob0>so1-ZYf$E8r_woS?pi*Lop*cnl7IkgsRtQLb%3$2^L(iDryocZ zazt!;WEh{Ee)!bbi%PC}uynJ!pu3~VyyQltw`2O51?`Ut+a1}Dzk1RdEv!ojs zNqF7$fY|@G=_Q2xD<*XOWr2?_cltlk1OYaVJ4Ih={NrpeGgcUar^q}3Tt`JA=kgi{ zo#)zXcm2P3+sSt9Pf%|A-iQD(pIS-?x!-cHIiaS0E8EKukm7oJSCgi!yl`M?N=jZT zZUp06$@Pke{?={q3+P+&$flajCzNASeHZ0*&raJT!|?0i-kqhmCnVQ?lO5)TL8hzax; zem)YoiF@y>m#l{&gJILOV%jvCuxhDj*Z8hpGf`_Sl8HuaEKDrcD}i}+)c08!ysBEB zII-fIl^1;M)WDL`l*+_o#?FO? zd*#71Dbh@Gm#&6kYNoYlBCCTrFYO0m&cGd~EGbicl7x(x5m{7dY`s7w>4@ZrP}vU@ z94fW3&ZR*&g@xWqHZp#$hVlz40dS}=Mum6wNOF*)^0ey#%IifZZR3Z$v1owG5}2AOUTSwRNKGR^6rL@ZR`Kx z(==y$7D=dsKl>=Z_%q|{JqO(iIXs%}SGyE&PDuifs=Y&HKO}WrQ$FzC9>1l|tp}KT zG8TUgml*fNx4IUaI8ak`1h*>`?@_W@vO*Vt)4s$m%)Brj>gjPYRvC4Rv1cxB=6D4>y(OC}*s zrW`(mBHjBmk?=}#evski6QyU_;_$xt(Efq6nfWk{dBnqqhwHfJ<%|{T)Gq4? zVQ@~9AA2{%NUU94AltCH9@4GGn6kOTFI6mXq z_b$w3<=Fsr?sA*aEtucGNRmv2=&zo@vsv~8bt!cRyn9key}hBvpWddpK`<=%0h$B# zgPoRC7p#%6QP#XDwQU((s~aBKLwh+ul=t z^}ciKR&+ltq=LD&l#=ix;8%9p4DW)K|97@uqV_$Z9oJXBn&yZz6KtrFqf6yxhVn_H z>|3GJfjl~3H80~kCe2Q5n{lq3#r20s?OoP1yuT>}N(1z!_@>J!J@9B=B-1T>(eI(M zdLb!hyLb(kzBd9jsjyhyCO79%)}>o&?}^H^ah%(?g2pIYYnEnivLfmwGnC|zneA2b zW7BFp9q6+<`8(H6&5BLz-LH-+v)n93Sp=M%IINrm?2_WK7-{iu0C5Q{#s%BTM%_P^ z&V~#Iklv+C=ZYUj6Q4zrouQwXIU+mn>YQogVuAv)GWxb#RC+(`DBwq?ZlD#fOy_XJ z>PgLjBEqCTYdwArE0&fl{v37?rhdx_6q-VnzMQa+>q#OI%rVe?e4JXm6E{`WSI2gx zR$QjcWuNJ3lozTGLy!ks97k+#ThC6ETj?pyw0u*jh^p|VKTzMBp#7Y!fx}a3Fmlx8 zskYy5Sb85MA^W}{A?&2cC!X^5)w367^YhOmewzaosGxo(_=;e7=xUfJ0KBZ2m~r>Y ztV)PwgDz8}!I;*GRVuRl=**~?^Lhs-QjG2;haz0i<*w3*q`TCrH&nMr& zGo&!fXfC1l#+$;>C075y+b%o0E$jgPhvG%1knwhf5l`5G0M^I5q|8ZquB}cLoR_MV zgGqy>NW446K_HIrwEX48@52;HMzK4 zO#-^Oh5P7rR%tF1L*{5|PdIpot#RLLMBjt99D)57(zmdW38RhK`6#LNWu2OkSk+x8 z_DyKq8-#c)7%9Xj$p>G_2Y$MCyX3=ek=9bp)7b=(?b)GCgW%r=?Fgk~Y(1V!;YjfB zN5q`01z>$7UE-Au7KZWkG2Xv17n-(j>$F^q%_*o!EAaeM;2u@tZ6@v;-jJz8XExw&CY+B*3}>Fh<{S`{UhL7H6bXRwf{FZHC2k?|=SbmaImPr+xkKqFs{wTD zf&=ez0T>Kr&g0!$1qLogD21>!OQfo2)>5ljzgzBGd!nldaN@y-0Ra%e2VDVL0ZyUu zPVpu%NMhpqP@mTl*S4}`+_uAVzVdFz{7G~%&+Jb>oZ`pG=jdXyW2(Fc`VXg*(rcxe z%`>0O!yV`G*si^WjQfKHtI)HuMT<-+ernLF7&*3Z3OBKDY8I za0nvdQ-~w_AR)JeTfbwKyeY)H$v1s2ap+on-GuJW_r`rWiO)v*G_^p3%_#apDXCj2 z|IDBr@4G^50D#QO5#QpRW=kC0yaZPCLA^6@~cjcDuQqs$j-Mh6o*R3D~@zfgu&mW z_JoB&NU!YOSPS5t#7V@e^Vz2fBs`|TQz5(c1y0wjKkKYLOVOP%Rxx<8IRgvR!i_~A z7A+7x`H|Q6RNo2luyBHf;jH~b^Gnfg1|Lc}nH9+ETgz$s8JT017~aqD?i;L&3K~yX zbW^zdh&<<@eQkY$^?4OW``?vT7orP`MH&Qsc*F4fPR-xQi27EOk(<0@lHBJ=;W1I* z;0#3^98er69a{SR%P?>lE#Gi>7as>Y1a`nE%UqugZ$JCAY`eU&65N3}z7mjNdnv8j5HQst>L3R?0<=Ns7fj)WtD~Rvba;IYNElTC~7zc@hf|P1u7@ zZ?X#Z#tsV)2l-Q4+7(j~FqTm41ZVfIuTq^x_p-JwquKooHN8)B5qR+kf~SWyb;)WN zQCpfd%26A$`dR*U9t0@bd#-?O%88mRV_aFKJr(cRaq238iyIx&DJ%DZdVHIXFI8Z6 zV&&LjzS~AKiL4f$_Rf7y7BF=2ZcBZ z?EIy}qnpecq9Qiw@=T=RLx+g6wp@esV;&wlA_+2{u$O0d2whs)bm3!UC$z7`R%eQ< zqD6v?o9`XNAB{3EFVT{_bm(W4-#XBE6xNsFJz`Bzw=h$FIw!kfl;HkWV}uA;7*pc@ z!!jQ9Q@-^5w`IxBw+(B(75?(-t8WUEVrz#7h(4syh3;M~7EeasuiuNs`i)|1V#0;M zK;kW{U%5-&k*Vrnl3vy?hf!t?TrABsy;C1P)Ha4ZZ0KAqhM#c_eTAvTbbJq+OsBeJBMn$Gj1hy{ef$5NkJhf_QDe+QCprciFxk&dp9k!sr2Q8%gg3nM#ALG_MOqvZ_&k;XxA0JT|(ifVGBUVSj=e zhn^f5LdOoX4AzKivaH24^)P7_5QU zmwLFX*#YAouOX96aud1VPRChTs&}el+YNEQKB7DgdWK@uMx2@^YxY_+g$*P9T~bVv zESM|{&2S{++MrtJ&?ngR$kIkB+u{DMBH;ksJXaHgwUxPBWGnk4-ZQ3sy3; z*7RNxml>EY<-dIx=J|Ae)jQ27RRD}@D^hxw>d0PYluiu{sr(M_Pg}__EeyU^GZb-L zD#=4|h-zdNE&wA9Re8w5LSGPGV!UO{(5-ht|FN(8Slw{G3JZ69{EX;X$nHTk*W9OO z-ewi%jt5G`GXNx6T$>mgJ`At@qm&_6T?h}8QG%3#^KD9h!qlhMi64!NRJZnot{S@d zx;G5BM?&HdQX0{%K1}a9;_IVA?CvRzW;jXo*<*6FmgMG8GkOK8& zs%x{oI>fe$EOBrQTw}{ThPh0rI-{|sGOm^5|I{QH&?gn;UkX=QXBn2!O>KuGW#T078x1Y(cqU8J>u*Ic1W)e zO)&lWjgr;SgT~oXgBr{bP+@H$4Z~YeU>O#ohI;Zv{e+XBgtPT6Y~vA<1Hewy&~nq1ssTYhMP?P#VcZ%plVds9A_ z@uB74g4-ubn`XID_CWGwVClKH`sOBJ%<}7LGk;g)!Yzo?4IB(p? zi--T9VSNIn0B*yr17D(_;G5ulp$Pi4QwxY|NVS&gd-l{mRp|es?+s)uEE1F+Ko+ zS-l(LjiXL#jSYZa@3-b8P4hGupH>*7Mz<04+AOg+39j~$=HPN%qhpiznds4(3#O4@ zh_i-0W(+|zg(_BcS+1aKf8*u@Nz6gjEWhZIN4D*M7Tl@fQrWw(EKP2(b zq3Vt)>gFlH&hz%*Tg;W->%EY9Me!1MVu0fx?uFXV)S=XeK)6Vwx@M>_ymFo_;7h~OmS;S zZKKYQiHCcqjWW2>q}6I3Q;zr3;Rxz+x2Seh5*9x+%BOM$M7;O?y0hUf?2%aqA59hF zkj^7wWZ9#KG0MpvA|OioQI@0#W!^e2^n85KZ7kj3>;+dHyp5KK>Klc3Vns|&N`69i zRB~AM(F&#tb^m+e+imFrq&&*+%gN)b{X#U%txj}otI%-ML)hbr*KM*$ND)ghNU0B}!hxY4kGxcghq}Rt-7dvpnCADuT;8@b-p|$k$)>xh zHI*(6=lVnSbh4GYOv_@>*%q9ifPy7|!50w0+)bxyq0o?hi~w zl4X=mmSRjAATxr_SPAalWPDJ4r9zlCU9MVj(ans*mAIYs#rp7Fp#tr65KKj z&?|{N_9W`s<{&i&;+)1yd-xtNb*#0xB`F;85?)(%yR_gVwTv3I#y@Wpq;#&Tw=*gv z@JEnC94ukwFKZGj0&&ZDYJ z%GVxxCr{Psm1oZMHjLb90Apzm4d-q6uJYZu(Rig%Lk_DS`RE=#sKhBZ#!AgpyAXM_ zY3R3K_gDdD3gIh(Brkfz$@^cYRMKSB(%DqfIV3oX(F^V7L^)PO*~D5GEZ$%}Bs%m2 zeQZWyvIe%sGGlabyIS`pAQE{tpx7(_0zTIMvN&fz&qhn0spWe`i?K%ptB{zlq%o2? z4s+?ePc}6sC?u=wzF7N<$TSjc=FmTt{egB8&N_iw((>>WH8#T&dM3jS1Og4HX6|FW z4a)vRxOUqzo*s@cu6=|($7!v8%M(AA&dhdf7+M?sW8zb-xtZfsXpkJ!xq`g<K)& zfFv2Ayt9I1Z2#0J#{zR)uhHHdj9TJ~yammh#=9fLGV3$CEOnF@QEr!Pn`^xO#ZxO} z?Hd($;6AAn{ryz_Lta^Ua_FQu?zuG2AkzN5#Zqu}qP4LnzNCsm!h6NvP5#e7UGpT9 zO$3(CkIkeDtb|p5B?u78BYY`VpjX-cdBOvu+X-25g!yuOkb8c+ju-YfMo88Cmlx-o zmjf3xXqWilPMpz2JB{{@_CqI=^VpcFn}g3?`Xbvy6&-C1l8ARLG+CW;A+8zlD?mkw@Bx+s{^m?kjwG4il!OX5$R<;GNA z!4Ek_uRKI9Jw&cJjI2Dr?Y$9aM+@OVhv&j#Dnm}4gDXFR4sg8@*4p?cDe3Dg2mowd zRT`n&qZaLT_;n9CRsA3`k?^+jv@IT)2oB;ymN^*s@ImSb6}e0ZYq66m!cR(_Arc!d zGRe0`%1gX6T26WjN%~^g8l~^rPrTa*U!9OLUT$SB*=j#YiZDhItVc(PhHA*7qP;j+3Dq)4ftRO+;l z{q3K?rs-Ogk2Jvf_39c8k@9p#z*?&2m69u8(!NOOr0c4}aWg3=UnOfNloAyZC>7D}$>^$uTt(+C%Y9}gBfDXrXss#z#*uU5qn0+tT4zxa+NubPNhoyl^4Fx76ym+^#JQ zbXm zvqRK7y9peZ(pjP?3QYC$RGmxhEfd&^4qfO_tdEH5GuFqGC)w~Zx}l7E`!RoclD0qt zb+=G_&LR_2_3~Fq%+;0A&f;8ahCu(1B2RE4PgEi&R3c9wjp78`yHt-_x?x? z>aIU*8o6AjiW(7zCAodi6@1kc>~1m@co8>)FuvaZI|BX@d0v${vTQkZ=Joc<`&O6f zCvZfuIq~+CVZA-`u6Ie{LBAWp<8hsB^_XVkR~ykczA7^AyCSJ2Mimn`gt9_;ch&ZL zktw#aMw~OYtKnndmGm)V-1k^Si19KCDl{fPAx?3NnX$o*?$7X!BF;Gk`P(%`uGnR& zb)j?gX|yMgA(UpiVskQtpK3(%R~&MuJG(I+Ut8>_C)CX(@2Z;I4S)Z#19$!&Hg4nL z>&E)K(@tF;w_1})1i^!kfd*>;7{hpnj38A=R1t0v`u^>b1hnVgnJteZxWOe|Vur9@F8gI_goznaY;DH7h(L^;qjSvUHwNy`7A zuM}^QHELX(^AU{Hg+?*nm3}Tv){B2pz__?83n=4k?Ma;-@S9mJy50{Y@JSOh43=g2 zw%%N_UJ8zrf&PZK`6Yhgb8l47s08L5FAvlB+%wN}Fn#G=OBO!qy&`mu83c}0R_m6j zJVIx-aFI+c#!pSNSUXJNmfKw6qVQ=_+y&-NeurMSA0p8{qWbu5hV{C)2J&roQJGel zsAbp@uM)*~pu>Fk&))?;9f(ziXsbj+!C70at3y|!BF$$yteK*o@dXn7qDuR5zY{DF z>kA<_qo{0f%l74O8MX45{QF%*KlM|r{SFA$7Pet+@k+QFH;dr+ig#RESPBma_&VYL z8GN^gwpkLiqR1_{%QE3i60NEO+m><6Ls81;|dpN{&Ze_U++ zGA{U*FV+!`xQ2nw?Ym&tsy`&`mnp+e+a$s2@ILp7*Gvo(GX%anZQA$7F9N^uNh zwAZ7a=2_WL9-r(Rk`;UjG5U8NMTywPr|4ohsoT^ipaWgY3%#g~yWV zDB=Eb#COYup6yyo_%Yx4UX*s#95v4(Piu$cQ>kxoRa$f(mknVYVzfUeQPyyRT4edj z%rjKemM04n)$ZA$o)?AE);}C{xbN%6UuT|``gbe&w@_5^eYgtUCnz$!ryRL^KhkGJ zpQP22qQp_ZG{JXC07X_bk^1=1zX|NL@sUvnDETEx(TuazA}CK2#LF-#b#72PX7sfd zi`~IVZkhR^^a$lc#I+A&jQ}`(2$+;9EQnr*#|=LA-VG^0PL-v~2s77NYSlxoszb*F zZI_k;gu!^-o*&e~L`4ILwZZr~2MW-Yc$%q)kqY5^$z2Ry84vph-&jtY-O-~k39xKgR zpo8kwSshyGjiL<)G)A9J-3nK-891Ab7rYlhx1dFn%!kJB9qIkGE`zxvI^+1fIx+Q4 zWfi?1vdXTFl6QD(IRB^tFRAbGYcxIGXnC4LJAViKK8%d4shmy?%@pyPqCMpa&pinN zwJ?DDCT9VenmW^vR5MZ`2B;z$O?)>uK^$ z#}bE#XKcdPN&?1r4XFg$VrU=F(dkaFhi!k+*<3MOTnTfv=4T2x5w%D09%g?*dYTl2 z)J9~yGrM(By(M_uWVi05I`4~eZ^zOj)P->@C};@hobY{{<+jMY&cVS~ukJdVN31on za&Tf#Z)?c+9vzNBj=PMmsvnYb2+(p;lRwVa&OimZ9$(aaghhphW+9gb3v$e|w3g0B zWao%*6mnO^&ofa#*wNwPCD16FnKB_d89IH~QG86IJ+awyLBeID$TFz_PPt`bly-};++md3 z&8oxU_cJu7R(ZwRH})>+vWD$){PX!u>J&9Sh2L^mFxNB+m*e5BsFwhrbw%nB-%mo& z0Ns%_-JU7+A8!44TM7CMI4U%9g*d6&&U1KrnPW&NM>9yNL5h$w*o&Nm!-DKHWQ4=a z2$s>5tuldI0cAmjJNz}r{I%9=Y*vudrz=b6)_)>YW%0&?yl%6+fNt5uEqe*ZSc~^V z$faaqcvn&@@P+s7=bMa}pg_9rJYRo@w^ILQ3?i;k{n8z8kn>O$Xlz+*IO>1hI z+itp(5ZX!gX*Gb3(S5HYmhiX~(`eOimxi&F7qw`VSU*-|(dyi9R+S-dD4)5*%bD-R zW%}EGgy>u1dMn{lJx_zHs>S<%Y-&QHMT)YYlRPnJgN7DaEPN$z3pZ$%co&Sd6P&ay zdtol1-($`TU$zmK7 z={DjykrZ7jlnhE83`&)R=@?u0@iQ&Et)$qRG8tP9?!R04d;!My(E~*bokc^%befgL z1MMt2+$<`+92$<2y)DD`2nSL#C}qaBWk|p5G1K8Pm&g!M6bG&&mj==rJINKeYPL7( z-YcTwL0B0_+uLn!+gis(s~vFvfM0FwnwfQLtOh4B$aY>^v#PO1%iI)Fe6puSk7v#J z1E38A)qFzqF*N)g+DsR47V8n#SA_R>6$`eeI?0$HS;3f?m{);t)}hi~92$26%|{liX6kLC~Q@I8=i(vQv^Q7v(Oe zOlF^Q^#Qyc&}l>e%32vG;=FyF?MBveD^D7@)WO1-J_18^#$k?aLv}qpO&SyHHp$L&hL*oK#lEBoJzJ!iL>>Cbbp9& zyX&pZAeqG|p266W`AyHlWoRS(sHPYsFca)AD(ja%IdUKT&DU}pi(Lz_bYE6?sKUyuOPqI7|s>4F6JfCFeQTq>H zM6g%P#jrt;YS6|+bq#W|+(X=;yQYAz6qhQ@P{MgJ>mE%f<;jp8hCdLoK#Fo}qd70> z&>ai^E%5^m{O78_TCIwjs7mzuo~dbDixruk*Y$Gev{WscX9Zb|CeoIS9qn7E;0cwIFG05-r| zu#kUWF_EgRBTV(%L|Ql8;Rbt}Kc35m;kf5DnT*CE8p6Yl6A?-7;)@Q=v=(6+%&D=#?6 z@KJs$NU$K@0~K>Gw~)lvZo&YOvM3_}0u9nD24^5s8KN>e19A8@NHi!k#%Pe2Oz!~E z**8*1$z;VpGzf^#5J<2fmI5P>ly6k3Uv!#(OnLx3BM6Zh9G3-jDl|TO4lDxlA1YX% z3`npb-UIMo3I3Silhu16q{t$u0Dj}aUlq*!vdnz4OuRCTJkp@HJmr#j$|?Q?z#;aS zU6g@Mgn><%o>l143&Dph0uP?^KVas&&%}F=iRT_8_uXe)cb)<`Z$IGx+SB`sXSm_I*(WcB{XfouiuJ)Xb=#eA&_7}ECtYT0GM9_8kE_9 hCT0rI)+m5%{|_1}09o`ByVC#w002ovPDHLkV1g}+>B9g3 literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-editor/machine.json b/corpus/math-edit/native-editor/machine.json new file mode 100644 index 0000000000000000000000000000000000000000..d77b6d02c2807f7f771543d921df076ba6c6b383 --- /dev/null +++ b/corpus/math-edit/native-editor/machine.json @@ -0,0 +1 @@ +{"name": "m6-e6af28e4", "hostname": "ONE-M6-E6AF28E4"} diff --git a/corpus/math-edit/native-editor/notebook/Open Notebook.onetoc2 b/corpus/math-edit/native-editor/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..adaa534b7ba36343fe368f97feaae448528bbfbc GIT binary patch literal 3764 zcmZ3e|KIuM`!b(-j|5(YE0x7-U%1(NBK?KiMr9et4GSM;FrWeZyR!tOCw}!@dO>{R z+Y{?_7K;rSCMqF)(Dp{IG1n9AVY0mwC(ME-89i>J?U^E1VVF&;Kx_LK; literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-editor/notebook/links.one b/corpus/math-edit/native-editor/notebook/links.one new file mode 100644 index 0000000000000000000000000000000000000000..7f26a4000599a0620938af93b9d0b24e8571fdc0 GIT binary patch literal 19184 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 SCUkZ=U=gsxYpO3jdGa5(@}GVH literal 0 HcmV?d00001 diff --git a/corpus/math-edit/native-editor/read/environment.json b/corpus/math-edit/native-editor/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..b4cc83142b43a0c21d9c89c20735fa101afc7717 --- /dev/null +++ b/corpus/math-edit/native-editor/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-E6AF28E4", + "cold": false, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/math-edit/native-editor/read/hierarchy.xml b/corpus/math-edit/native-editor/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..fef7a29b591f027a53d6922d7dead29b56deefc4 --- /dev/null +++ b/corpus/math-edit/native-editor/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/math-edit/native-editor/read/page-000.xml b/corpus/math-edit/native-editor/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..fbdbe2d50c9852606667b37041ad0bc6f5848ea1 --- /dev/null +++ b/corpus/math-edit/native-editor/read/page-000.xml @@ -0,0 +1,3 @@ + +the Rust site]]>a1+b2]]>xi2]]>a+b]]>∫01x dx ]]>∑i=1ni ]]> diff --git a/corpus/math-edit/native-editor/read/payloads.json b/corpus/math-edit/native-editor/read/payloads.json new file mode 100644 index 0000000000000000000000000000000000000000..1ce91a413d6fff4d58765187b76756f0e97ae843 --- /dev/null +++ b/corpus/math-edit/native-editor/read/payloads.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/corpus/math-edit/native-editor/run.json b/corpus/math-edit/native-editor/run.json new file mode 100644 index 0000000000000000000000000000000000000000..9e670c7143179c57e2107d7c15c06d0cb8b81a64 --- /dev/null +++ b/corpus/math-edit/native-editor/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/Users/clo/dev/one/corpus/link-edit/candidate", + "expected_pages": 1, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/math-edit/native-editor/scripts/cold.ps1 b/corpus/math-edit/native-editor/scripts/cold.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a0b99e7aeb86f4dc10032537800501a52ad65b4f --- /dev/null +++ b/corpus/math-edit/native-editor/scripts/cold.ps1 @@ -0,0 +1,27 @@ +param([Parameter(Mandatory=$true)][string]$Root, [string]$CloneHost = '') +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +if (Get-Process ONENOTE -ErrorAction SilentlyContinue) { throw 'Close OneNote before resetting its test cache.' } +$key = 'HKCU:\Software\Microsoft\Office\14.0\OneNote' +if ($CloneHost) { + if ($CloneHost -notmatch '^ONE-[A-Z0-9-]+$' -or [Environment]::MachineName -ne $CloneHost) { + throw 'The disposable clone hostname does not match this machine.' + } + New-Item "$key\Options\Paths" -Force | Out-Null + New-ItemProperty "$key\Options\Paths" -Name UnfiledNotesSection -PropertyType ExpandString -Value 'C:\one-tests\Loose.one' -Force | Out-Null +} elseif ((Get-ItemProperty "$key\Options\Paths").UnfiledNotesSection -ne 'C:\one-tests\Loose.one' -or + -not (Test-Path 'C:\one-tests\profile-original-cache')) { + throw 'Park the personal OneNote profile before resetting the test cache.' +} +$cache = Join-Path $env:LOCALAPPDATA 'Microsoft\OneNote\14.0' +$parked = Join-Path 'C:\one-tests\caches' ([IO.Path]::GetFileName($root)) +if (Test-Path $parked) { throw 'Choose a new run; its parked cache already exists.' } +New-Item -ItemType Directory -Path 'C:\one-tests\caches' -Force | Out-Null +if (Test-Path $cache) { Move-Item -LiteralPath $cache -Destination $parked } +if (Test-Path "$key\OpenNotebooks") { Remove-Item "$key\OpenNotebooks" -Recurse } +New-Item "$key\OpenNotebooks" | Out-Null +New-ItemProperty "$key\OpenNotebooks" -Name '1' -PropertyType String -Value "$root\notebook" | Out-Null diff --git a/corpus/math-edit/native-editor/scripts/read.ps1 b/corpus/math-edit/native-editor/scripts/read.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..476094ab1e0c47077988a6461db2080cf208642b --- /dev/null +++ b/corpus/math-edit/native-editor/scripts/read.ps1 @@ -0,0 +1,142 @@ +param( + [Parameter(Mandatory=$true)][string]$Root, + [int]$ExpectedPages = -1, + [switch]$UseCurrentCache, + [switch]$Pdf, + [switch]$KeepOpen, + [string]$CloneHost = '' +) +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +$notebook = Join-Path $root 'notebook' +$output = Join-Path $root 'read' +if (Test-Path $output) { throw 'Choose a new read destination.' } +if ($UseCurrentCache) { + if ((Get-ItemProperty 'HKCU:\Software\Microsoft\Office\14.0\OneNote\Options\Paths').UnfiledNotesSection -ne 'C:\one-tests\Loose.one') { + throw 'Park the personal OneNote profile before reading test notebooks.' + } +} else { + & "$PSScriptRoot\cold-current.ps1" -Root $root -CloneHost $CloneHost +} +New-Item -ItemType Directory -Path $output | Out-Null +$app = New-Object -ComObject OneNote.Application +$notebookId = '' +$failure = $null +try { + $app.OpenHierarchy($notebook, '', [ref]$notebookId, 0) + $process = Get-Process ONENOTE + @{ hostname = [Environment]::MachineName; onenote = $process.MainModule.FileVersionInfo.FileVersion; + powershell = $PSVersionTable.PSVersion.ToString(); schema = 'xs2010'; cold = (-not $UseCurrentCache.IsPresent) } | + ConvertTo-Json | Set-Content (Join-Path $output 'environment.json') -Encoding UTF8 + $sections = @() + foreach ($file in @(Get-ChildItem $notebook -Recurse | Where-Object { $_.Extension -eq '.one' })) { + $id = '' + $app.OpenHierarchy($file.FullName, '', [ref]$id, 0) + $sections += $id + } + $deadline = [DateTime]::UtcNow.AddSeconds(300) + $previous = '' + $lastChange = '' + $stableSince = [DateTime]::UtcNow + $settled = $false + do { + $pages = @{} + foreach ($section in $sections) { + $hierarchy = '' + $app.GetHierarchy($section, 4, [ref]$hierarchy, 1) + [xml]$xml = $hierarchy + foreach ($node in $xml.SelectNodes('//*[@path]')) { + if (-not $node.GetAttribute('path').StartsWith("$notebook\", [StringComparison]::OrdinalIgnoreCase)) { + throw 'OneNote opened a section outside the copied notebook.' + } + } + foreach ($node in $xml.SelectNodes('//*[local-name()="Page"]')) { + $id = $node.GetAttribute('ID') + $content = '' + $app.GetPageContent($id, [ref]$content, 1, 1) + $pages[$id] = $content + } + } + $signature = [String]::Join('|', @($pages.Keys | Sort-Object | ForEach-Object { $_ + $pages[$_] })) + if ($signature -ne $previous) { + $lastChange = $previous + $previous = $signature + $stableSince = [DateTime]::UtcNow + } + if ((($ExpectedPages -ge 0 -and $pages.Count -eq $ExpectedPages) -or + ($ExpectedPages -lt 0 -and $pages.Count -gt 0)) -and + ([DateTime]::UtcNow - $stableSince).TotalSeconds -ge 2) { $settled = $true; break } + Start-Sleep -Milliseconds 250 + } while ([DateTime]::UtcNow -lt $deadline) + if (-not $settled -or ($ExpectedPages -ge 0 -and $pages.Count -ne $ExpectedPages) -or ($ExpectedPages -lt 0 -and $pages.Count -eq 0)) { + [IO.File]::WriteAllText((Join-Path $output 'previous-signature.txt'), $lastChange, [Text.Encoding]::UTF8) + $index = 0 + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('unsettled-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + $index++ + } + $hierarchy = '' + $app.GetHierarchy($notebookId, 4, [ref]$hierarchy, 1) + [IO.File]::WriteAllText((Join-Path $output 'unsettled-hierarchy.xml'), $hierarchy, [Text.Encoding]::UTF8) + throw "Expected $ExpectedPages stable pages; OneNote returned $($pages.Count), settled=$settled." + } + $index = 0 + $payloads = @() + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('page-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + if ($Pdf) { + $pdfPath = Join-Path $output ('page-{0:d3}.pdf' -f $index) + $app.NavigateTo($id, '', $false) + $app.Publish($id, $pdfPath, 3, '') + if (-not (Test-Path $pdfPath) -or (Get-Item $pdfPath).Length -eq 0) { throw 'OneNote did not publish the page PDF.' } + } + [xml]$page = $pages[$id] + foreach ($file in $page.SelectNodes('//*[local-name()="InsertedFile" or local-name()="MediaFile"]')) { + $bytes = [IO.File]::ReadAllBytes($file.GetAttribute('pathCache')) + $hash = [BitConverter]::ToString([Security.Cryptography.SHA256]::Create().ComputeHash($bytes)).Replace('-', '').ToLowerInvariant() + [IO.File]::WriteAllBytes((Join-Path $output ($hash + '.attachment')), $bytes) + $payloads += @{ page = $id; object = $file.ParentNode.GetAttribute('objectID'); + kind = $file.LocalName; name = $file.GetAttribute('preferredName'); + sha256 = $hash; bytes = $bytes.Length } + } + $index++ + } + [IO.File]::WriteAllText((Join-Path $output 'payloads.json'), (ConvertTo-Json -InputObject $payloads -Depth 4), [Text.Encoding]::UTF8) + $all = '' + $app.GetHierarchy($notebookId, 4, [ref]$all, 1) + [xml]$finalTree = $all + $finalIds = @($finalTree.SelectNodes('//*[local-name()="Page"]') | ForEach-Object { $_.GetAttribute('ID') } | Sort-Object -Unique) + if ($finalIds.Count -ne $pages.Count -or @($finalIds | Where-Object { -not $pages.ContainsKey($_) }).Count -ne 0) { + throw 'The notebook hierarchy changed while collecting page evidence; repeat the cold read.' + } + [IO.File]::WriteAllText((Join-Path $output 'hierarchy.xml'), $all, [Text.Encoding]::UTF8) + Write-Output "Read $($sections.Count) sections and $($pages.Count) pages." +} catch { + $failure = $_ + [IO.File]::WriteAllText((Join-Path $output 'failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + throw +} finally { + try { + try { + if ($notebookId -and $CloneHost) { $app.SyncHierarchy($notebookId) } + if ($notebookId -and -not $KeepOpen -and (-not $UseCurrentCache -or $CloneHost)) { + $app.CloseNotebook($notebookId, $false) + } + } catch { + if ($null -eq $failure) { throw } + [IO.File]::WriteAllText((Join-Path $output 'cleanup-failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + } + } finally { + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) + } + $app = $null + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + if (-not $UseCurrentCache -and -not $CloneHost) { + Get-Process ONENOTE -ErrorAction SilentlyContinue | Wait-Process -Timeout 10 + } +} diff --git a/corpus/math-edit/native-editor/source.json b/corpus/math-edit/native-editor/source.json new file mode 100644 index 0000000000000000000000000000000000000000..14786084a474f1cc0a6f522bd49c8104ad3627f0 --- /dev/null +++ b/corpus/math-edit/native-editor/source.json @@ -0,0 +1,14 @@ +[ + { + "path": "Open Notebook.onetoc2", + "bytes": 1604, + "sha256": "6731c4214437fe1cb6aa347b0004542b7f7e4260f47773bf9ec07c4e894de47c", + "mtime_ns": 1789206821144296891 + }, + { + "path": "links.one", + "bytes": 6128, + "sha256": "0cfb356ed374fe919f73fb73fdbe5d66e0baa484d4119f70074d9f869d6db78a", + "mtime_ns": 1789206821116200533 + } +] diff --git a/corpus/math-edit/native-editor/teardown.json b/corpus/math-edit/native-editor/teardown.json new file mode 100644 index 0000000000000000000000000000000000000000..05a47793de40f322e745c4c4183727e3590ecf70 --- /dev/null +++ b/corpus/math-edit/native-editor/teardown.json @@ -0,0 +1 @@ +{"absent": true} diff --git a/corpus/math-edit/written/candidate/Open Notebook.onetoc2 b/corpus/math-edit/written/candidate/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..ed5695c77cfdffc62762c78f37e8fb316a61073c GIT binary patch literal 1596 zcmZ3e|KIuM`!b(-j|5(YE0x6u#hzRI{K_?_g@Heqj&Z3=GN1wbyR!tOCw}!@dO>{R z+Y{?M?+u)hd=`h!xUKt znVm8WBH2KCACMLR21jJgy5L*i-?{atiSvGLV{`}QA|W8oWk_TwVaQ<6W5{R7V@L&x zfbuj@wt)*sFfx3TVNikPI0l9zU%r3cSQWNJ5U36WL<$%hBG1%Ld@U{JvV6;Z6BeIY z|6r=6UobSt^XDGFwN1mNeTT&XS)RbNFgb{BOcElmD8kUdpppP2fB@ZikT^)$yBh`5 znKnLmnYAHzVa-l|Ee!#N2E7V~4h9yGE(Qhsu5tbFs{W!!XF^iVg<|Dccq0Un@Z&>aXeOu&I*LITt(u<1ZCkXaxA(uZ!I yFh~#xI3@t~LCeJeARn9AEI90hn2u^bD4sx`0=bt7h(Y#%XpkG1ZL6PxtOo$Bf6>kW literal 0 HcmV?d00001 diff --git a/corpus/math-edit/written/candidate/expected-mathml.json b/corpus/math-edit/written/candidate/expected-mathml.json new file mode 100644 index 0000000000000000000000000000000000000000..f3e305976b641ad96017eeb498f4301d01258a78 --- /dev/null +++ b/corpus/math-edit/written/candidate/expected-mathml.json @@ -0,0 +1,12 @@ +[ + "x2+y2=z2", + "a+bc+d", + "𝛼+𝛽", + "a1+b2", + "xi2", + "a+b", + "∫01x dx ", + "∑i=1ni ", + "x2+1", + "a+bc2" +] \ No newline at end of file diff --git a/corpus/math-edit/written/candidate/math.one b/corpus/math-edit/written/candidate/math.one new file mode 100644 index 0000000000000000000000000000000000000000..6cc857f4e22670ede55e5f5f426d0f12fecaf101 GIT binary patch literal 15424 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 literal 0 HcmV?d00001 diff --git a/corpus/math-edit/written/cold/notebook/expected-mathml.json b/corpus/math-edit/written/cold/notebook/expected-mathml.json new file mode 100644 index 0000000000000000000000000000000000000000..f3e305976b641ad96017eeb498f4301d01258a78 --- /dev/null +++ b/corpus/math-edit/written/cold/notebook/expected-mathml.json @@ -0,0 +1,12 @@ +[ + "x2+y2=z2", + "a+bc+d", + "𝛼+𝛽", + "a1+b2", + "xi2", + "a+b", + "∫01x dx ", + "∑i=1ni ", + "x2+1", + "a+bc2" +] \ No newline at end of file diff --git a/corpus/math-edit/written/cold/notebook/math.one b/corpus/math-edit/written/cold/notebook/math.one new file mode 100644 index 0000000000000000000000000000000000000000..9cc7e9560eeff1e97754164a05eae7255e13c196 GIT binary patch literal 16920 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 + diff --git a/corpus/math-edit/written/cold/read/page-000.navigation.json b/corpus/math-edit/written/cold/read/page-000.navigation.json new file mode 100644 index 0000000000000000000000000000000000000000..af6bcb2175c02024ff0ca87879c85b382404985b --- /dev/null +++ b/corpus/math-edit/written/cold/read/page-000.navigation.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 800, + "h": 600, + "error": null, + "win": { + "title": "Equations below - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/math-edit/written/cold/read/page-000.png b/corpus/math-edit/written/cold/read/page-000.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7fd663288f5eefe1230686a1399567c9d6f8d5 GIT binary patch literal 39901 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 literal 0 HcmV?d00001 diff --git a/corpus/math-edit/written/cold/read/page-000.xml b/corpus/math-edit/written/cold/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..5a2a4051d0554dd8dce44a9ea20aad0d69dd35a1 --- /dev/null +++ b/corpus/math-edit/written/cold/read/page-000.xml @@ -0,0 +1,3 @@ + +x2+y2=z2]]>a+bc+d]]>Inline ]]>a1+b2]]>xi2]]>a+b]]>∫01x dx ]]>∑i=1ni ]]>x2+1]]>a+bc2]]> diff --git a/corpus/math-edit/written/cold/read/payloads.json b/corpus/math-edit/written/cold/read/payloads.json new file mode 100644 index 0000000000000000000000000000000000000000..1ce91a413d6fff4d58765187b76756f0e97ae843 --- /dev/null +++ b/corpus/math-edit/written/cold/read/payloads.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/corpus/math-edit/written/cold/run.json b/corpus/math-edit/written/cold/run.json new file mode 100644 index 0000000000000000000000000000000000000000..068c5a4da94ffd56599463b3d8d1d9d2f744b81a --- /dev/null +++ b/corpus/math-edit/written/cold/run.json @@ -0,0 +1,18 @@ +{ + "notebook": "/private/tmp/m4/written", + "expected_pages": 1, + "author": null, + "author_timeout_seconds": 600, + "inspect": false, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/math-edit/written/cold/scripts/cold.ps1 b/corpus/math-edit/written/cold/scripts/cold.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a0b99e7aeb86f4dc10032537800501a52ad65b4f --- /dev/null +++ b/corpus/math-edit/written/cold/scripts/cold.ps1 @@ -0,0 +1,27 @@ +param([Parameter(Mandatory=$true)][string]$Root, [string]$CloneHost = '') +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +if (Get-Process ONENOTE -ErrorAction SilentlyContinue) { throw 'Close OneNote before resetting its test cache.' } +$key = 'HKCU:\Software\Microsoft\Office\14.0\OneNote' +if ($CloneHost) { + if ($CloneHost -notmatch '^ONE-[A-Z0-9-]+$' -or [Environment]::MachineName -ne $CloneHost) { + throw 'The disposable clone hostname does not match this machine.' + } + New-Item "$key\Options\Paths" -Force | Out-Null + New-ItemProperty "$key\Options\Paths" -Name UnfiledNotesSection -PropertyType ExpandString -Value 'C:\one-tests\Loose.one' -Force | Out-Null +} elseif ((Get-ItemProperty "$key\Options\Paths").UnfiledNotesSection -ne 'C:\one-tests\Loose.one' -or + -not (Test-Path 'C:\one-tests\profile-original-cache')) { + throw 'Park the personal OneNote profile before resetting the test cache.' +} +$cache = Join-Path $env:LOCALAPPDATA 'Microsoft\OneNote\14.0' +$parked = Join-Path 'C:\one-tests\caches' ([IO.Path]::GetFileName($root)) +if (Test-Path $parked) { throw 'Choose a new run; its parked cache already exists.' } +New-Item -ItemType Directory -Path 'C:\one-tests\caches' -Force | Out-Null +if (Test-Path $cache) { Move-Item -LiteralPath $cache -Destination $parked } +if (Test-Path "$key\OpenNotebooks") { Remove-Item "$key\OpenNotebooks" -Recurse } +New-Item "$key\OpenNotebooks" | Out-Null +New-ItemProperty "$key\OpenNotebooks" -Name '1' -PropertyType String -Value "$root\notebook" | Out-Null diff --git a/corpus/math-edit/written/cold/scripts/read.ps1 b/corpus/math-edit/written/cold/scripts/read.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..476094ab1e0c47077988a6461db2080cf208642b --- /dev/null +++ b/corpus/math-edit/written/cold/scripts/read.ps1 @@ -0,0 +1,142 @@ +param( + [Parameter(Mandatory=$true)][string]$Root, + [int]$ExpectedPages = -1, + [switch]$UseCurrentCache, + [switch]$Pdf, + [switch]$KeepOpen, + [string]$CloneHost = '' +) +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +$root = [IO.Path]::GetFullPath($Root).TrimEnd('\') +if ([IO.Path]::GetDirectoryName($root) -ne 'C:\one-tests\runs') { + throw 'Choose a run directly below C:\one-tests\runs.' +} +$notebook = Join-Path $root 'notebook' +$output = Join-Path $root 'read' +if (Test-Path $output) { throw 'Choose a new read destination.' } +if ($UseCurrentCache) { + if ((Get-ItemProperty 'HKCU:\Software\Microsoft\Office\14.0\OneNote\Options\Paths').UnfiledNotesSection -ne 'C:\one-tests\Loose.one') { + throw 'Park the personal OneNote profile before reading test notebooks.' + } +} else { + & "$PSScriptRoot\cold-current.ps1" -Root $root -CloneHost $CloneHost +} +New-Item -ItemType Directory -Path $output | Out-Null +$app = New-Object -ComObject OneNote.Application +$notebookId = '' +$failure = $null +try { + $app.OpenHierarchy($notebook, '', [ref]$notebookId, 0) + $process = Get-Process ONENOTE + @{ hostname = [Environment]::MachineName; onenote = $process.MainModule.FileVersionInfo.FileVersion; + powershell = $PSVersionTable.PSVersion.ToString(); schema = 'xs2010'; cold = (-not $UseCurrentCache.IsPresent) } | + ConvertTo-Json | Set-Content (Join-Path $output 'environment.json') -Encoding UTF8 + $sections = @() + foreach ($file in @(Get-ChildItem $notebook -Recurse | Where-Object { $_.Extension -eq '.one' })) { + $id = '' + $app.OpenHierarchy($file.FullName, '', [ref]$id, 0) + $sections += $id + } + $deadline = [DateTime]::UtcNow.AddSeconds(300) + $previous = '' + $lastChange = '' + $stableSince = [DateTime]::UtcNow + $settled = $false + do { + $pages = @{} + foreach ($section in $sections) { + $hierarchy = '' + $app.GetHierarchy($section, 4, [ref]$hierarchy, 1) + [xml]$xml = $hierarchy + foreach ($node in $xml.SelectNodes('//*[@path]')) { + if (-not $node.GetAttribute('path').StartsWith("$notebook\", [StringComparison]::OrdinalIgnoreCase)) { + throw 'OneNote opened a section outside the copied notebook.' + } + } + foreach ($node in $xml.SelectNodes('//*[local-name()="Page"]')) { + $id = $node.GetAttribute('ID') + $content = '' + $app.GetPageContent($id, [ref]$content, 1, 1) + $pages[$id] = $content + } + } + $signature = [String]::Join('|', @($pages.Keys | Sort-Object | ForEach-Object { $_ + $pages[$_] })) + if ($signature -ne $previous) { + $lastChange = $previous + $previous = $signature + $stableSince = [DateTime]::UtcNow + } + if ((($ExpectedPages -ge 0 -and $pages.Count -eq $ExpectedPages) -or + ($ExpectedPages -lt 0 -and $pages.Count -gt 0)) -and + ([DateTime]::UtcNow - $stableSince).TotalSeconds -ge 2) { $settled = $true; break } + Start-Sleep -Milliseconds 250 + } while ([DateTime]::UtcNow -lt $deadline) + if (-not $settled -or ($ExpectedPages -ge 0 -and $pages.Count -ne $ExpectedPages) -or ($ExpectedPages -lt 0 -and $pages.Count -eq 0)) { + [IO.File]::WriteAllText((Join-Path $output 'previous-signature.txt'), $lastChange, [Text.Encoding]::UTF8) + $index = 0 + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('unsettled-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + $index++ + } + $hierarchy = '' + $app.GetHierarchy($notebookId, 4, [ref]$hierarchy, 1) + [IO.File]::WriteAllText((Join-Path $output 'unsettled-hierarchy.xml'), $hierarchy, [Text.Encoding]::UTF8) + throw "Expected $ExpectedPages stable pages; OneNote returned $($pages.Count), settled=$settled." + } + $index = 0 + $payloads = @() + foreach ($id in @($pages.Keys | Sort-Object)) { + [IO.File]::WriteAllText((Join-Path $output ('page-{0:d3}.xml' -f $index)), $pages[$id], [Text.Encoding]::UTF8) + if ($Pdf) { + $pdfPath = Join-Path $output ('page-{0:d3}.pdf' -f $index) + $app.NavigateTo($id, '', $false) + $app.Publish($id, $pdfPath, 3, '') + if (-not (Test-Path $pdfPath) -or (Get-Item $pdfPath).Length -eq 0) { throw 'OneNote did not publish the page PDF.' } + } + [xml]$page = $pages[$id] + foreach ($file in $page.SelectNodes('//*[local-name()="InsertedFile" or local-name()="MediaFile"]')) { + $bytes = [IO.File]::ReadAllBytes($file.GetAttribute('pathCache')) + $hash = [BitConverter]::ToString([Security.Cryptography.SHA256]::Create().ComputeHash($bytes)).Replace('-', '').ToLowerInvariant() + [IO.File]::WriteAllBytes((Join-Path $output ($hash + '.attachment')), $bytes) + $payloads += @{ page = $id; object = $file.ParentNode.GetAttribute('objectID'); + kind = $file.LocalName; name = $file.GetAttribute('preferredName'); + sha256 = $hash; bytes = $bytes.Length } + } + $index++ + } + [IO.File]::WriteAllText((Join-Path $output 'payloads.json'), (ConvertTo-Json -InputObject $payloads -Depth 4), [Text.Encoding]::UTF8) + $all = '' + $app.GetHierarchy($notebookId, 4, [ref]$all, 1) + [xml]$finalTree = $all + $finalIds = @($finalTree.SelectNodes('//*[local-name()="Page"]') | ForEach-Object { $_.GetAttribute('ID') } | Sort-Object -Unique) + if ($finalIds.Count -ne $pages.Count -or @($finalIds | Where-Object { -not $pages.ContainsKey($_) }).Count -ne 0) { + throw 'The notebook hierarchy changed while collecting page evidence; repeat the cold read.' + } + [IO.File]::WriteAllText((Join-Path $output 'hierarchy.xml'), $all, [Text.Encoding]::UTF8) + Write-Output "Read $($sections.Count) sections and $($pages.Count) pages." +} catch { + $failure = $_ + [IO.File]::WriteAllText((Join-Path $output 'failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + throw +} finally { + try { + try { + if ($notebookId -and $CloneHost) { $app.SyncHierarchy($notebookId) } + if ($notebookId -and -not $KeepOpen -and (-not $UseCurrentCache -or $CloneHost)) { + $app.CloseNotebook($notebookId, $false) + } + } catch { + if ($null -eq $failure) { throw } + [IO.File]::WriteAllText((Join-Path $output 'cleanup-failure.txt'), ($_ | Out-String), [Text.Encoding]::UTF8) + } + } finally { + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) + } + $app = $null + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + if (-not $UseCurrentCache -and -not $CloneHost) { + Get-Process ONENOTE -ErrorAction SilentlyContinue | Wait-Process -Timeout 10 + } +} diff --git a/corpus/math-edit/written/cold/source.json b/corpus/math-edit/written/cold/source.json new file mode 100644 index 0000000000000000000000000000000000000000..7e5fb30c38c8f532d9a9957daa8499516d02873a --- /dev/null +++ b/corpus/math-edit/written/cold/source.json @@ -0,0 +1,20 @@ +[ + { + "path": "Open Notebook.onetoc2", + "bytes": 1596, + "sha256": "bc31e9f663f68420b4f7684641e2a75abefddd97256074bae432dff0fff5244c", + "mtime_ns": 1789267920902398086 + }, + { + "path": "expected-mathml.json", + "bytes": 1536, + "sha256": "7c0f17965424fbfee0f952b0293a2daf5fcd7040d50b7482e90785cc52192c84", + "mtime_ns": 1789267920927591231 + }, + { + "path": "math.one", + "bytes": 15424, + "sha256": "70b09e61eaca321b6aa555316b59769f282843c7710c4ca311f1b5d2d7ec42bd", + "mtime_ns": 1789267920871282689 + } +] diff --git a/corpus/math-edit/written/cold/teardown.json b/corpus/math-edit/written/cold/teardown.json new file mode 100644 index 0000000000000000000000000000000000000000..05a47793de40f322e745c4c4183727e3590ecf70 --- /dev/null +++ b/corpus/math-edit/written/cold/teardown.json @@ -0,0 +1 @@ +{"absent": true} diff --git a/crates/notebook/README.md b/crates/notebook/README.md index e9b9ee4d9efe9223362d8366610e00664737645e..70ce70ea2b329dd4328c6264bea9cd80cb5160cc 100644 --- a/crates/notebook/README.md +++ b/crates/notebook/README.md @@ -14,7 +14,7 @@ diffs the supplied model against the page stored in the supplied local snapshot, writes the difference into the working image and queues one `Operation::Page(PageIntent { before, after, author })`; `before` is the page the edit started from and is the precondition reconciliation checks. Text, styles, -paragraph formatting, hyperlinks (external and internal), bullets, numbering, note tags, table rows, columns, cell shading, nested tables, pictures (insertion in paragraphs or on the page, position, size, description), attachments, ink strokes, paragraph structure, +paragraph formatting, hyperlinks (external and internal), bullets, numbering, note tags, table rows, columns, cell shading, nested tables, pictures (insertion in paragraphs or on the page, position, size, description), attachments, ink strokes, equations, paragraph structure, outline layout, insertions and deletions are all differences between `before` and `after`; the library never sees editor operations. diff --git a/crates/onestore/README.md b/crates/onestore/README.md index 793babecd34aa7639f4b5435ccea18be46eddaf8..bc267d205c498f34e9ea2a67ccec8b8f6cc6da13 100644 --- a/crates/onestore/README.md +++ b/crates/onestore/README.md @@ -57,7 +57,7 @@ harness also accepts `--client-profile release`. | `ParagraphJoin`, `PreparedEdit::join` | Join adjacent ordinary text while preserving inherited character styles and native text-identity rules | | `TextAttribute`, `PreparedEdit::format` | Change character formatting over a UTF-16 range while sharing immutable styles; preserve unselected runs | | `OutlineEdit`, `PreparedEdit::outline` | Change ordinary outline position/width or a paragraph's saved expansion default, preserving identities and content | -| `PreparedEdit::page` | Publish an edited `page::Page` as one revision per changed space: text, character and paragraph formatting, hyperlinks (external and, via `page::link`, to pages, paragraphs and sections), bullets and numbering, note tags, table rows, columns, cell shading and indents, nested tables, inserted pictures (in paragraphs or on the page) and attachments, picture position, size and description, ink drawings and handwriting (strokes added and erased), paragraph insertion/split/join/move/deletion, outline insertion/deletion/position/width and saved collapse state, lowered onto the typed writers with the model's identities | +| `PreparedEdit::page` | Publish an edited `page::Page` as one revision per changed space: text, character and paragraph formatting, hyperlinks (external and, via `page::link`, to pages, paragraphs and sections), bullets and numbering, note tags, table rows, columns, cell shading and indents, nested tables, inserted pictures (in paragraphs or on the page) and attachments, picture position, size and description, ink drawings and handwriting (strokes added and erased), equations (built from `page::Math` trees), paragraph insertion/split/join/move/deletion, outline insertion/deletion/position/width and saved collapse state, lowered onto the typed writers with the model's identities | | `TreeEdit`, `PreparedEdit::tree` | Move or delete a subtree on one page, normalize surviving containers, and replace an emptied table cell's paragraph atomically | | `PreparedEdit::commit`, `PreparedEdit::commit_file` | Publish the exact prepared image under caller-held exclusion or the conservative filesystem adapter | | `read_file` | Read a snapshot under whole-file exclusion | diff --git a/crates/onestore/src/page/math.rs b/crates/onestore/src/page/math.rs index c1205f2e1ba27412b1b69f5e0245fd5667c6bace..7ae2f63d495c769e352107e0daab7da9f9d5f289 100644 --- a/crates/onestore/src/page/math.rs +++ b/crates/onestore/src/page/math.rs @@ -1,8 +1,9 @@ //! Equations as OneNote stores them: a linear text where U+FDD0 opens an inline object, //! U+FDEE separates its arguments and U+FDEF closes it, with the object's kind on the run //! data of the opening character. `Math::parse` builds the tree and `mathml` renders it the -//! way OneNote's own export does for the kinds a native fixture has verified (superscript -//! and fraction); other kinds follow the text object model's meaning without a native check. +//! way OneNote's own export does for the kinds native fixtures have verified (superscript, +//! subscript, both, fraction, brackets, n-ary operators with limits); radicals, under/over +//! limits and the rest follow the text object model's meaning without a native check. use super::text::Paragraph; use crate::document::MathObject; @@ -96,7 +97,7 @@ impl Math { arguments: frame.arguments, }); } - c if c.is_whitespace() => {} + c if c.is_whitespace() => sequences.last_mut().unwrap().push(Math::Operator(' ')), c if c.is_alphabetic() => sequences .last_mut() .unwrap() @@ -133,11 +134,12 @@ impl Math { symbols, arguments, } => { + // A lone identifier, number or operator stands bare; anything else is a row. let argument = |out: &mut String, index: usize| match arguments .get(index) .map(Vec::as_slice) { - Some([single]) => single.write(out), + Some([single]) if !matches!(single, Math::Object { .. }) => single.write(out), Some(many) => { out.push_str(""); for node in many { @@ -163,16 +165,26 @@ impl Math { (25, _) => wrapped(out, "msqrt", &[arguments.len() - 1]), (19, 2) => wrapped(out, "munder", &[0, 1]), (33, 2) => wrapped(out, "mover", &[0, 1]), - (13, _) => { + // OneNote exports parentheses as default fences, whatever the pair. + (13, _) => wrapped(out, "mfenced", &[0]), + // Lower limit, upper limit, body; integrals take their limits as scripts, + // other operators above and below. + (21, 3) => { + let operator = symbols.first().copied().unwrap_or('∑'); + let element = if ('\u{222b}'..='\u{2233}').contains(&operator) { + "msubsup" + } else { + "munderover" + }; + out.push_str(&format!( + "{operator}" + )); + argument(out, 0); + argument(out, 1); + out.push_str(&format!("")); out.push_str(""); - if let Some(open) = symbols.first() { - tag(out, "mo", &open.to_string()); - } - for index in 0..arguments.len() { - argument(out, index); - } - if let Some(close) = symbols.get(1) { - tag(out, "mo", &close.to_string()); + for node in &arguments[2] { + node.write(out); } out.push_str(""); } @@ -199,6 +211,7 @@ fn tag(out: &mut String, element: &str, content: &str) { '<' => out.push_str("<"), '&' => out.push_str("&"), '>' => out.push_str(">"), + ' ' => out.push_str(" "), c => out.push(c), } } @@ -215,3 +228,96 @@ fn plain(c: char) -> char { _ => c, } } + +impl Math { + /// The paragraph OneNote stores for `nodes`: linear text with object controls, every run + /// formatted the way the equation editor formats it (Cambria Math, italic, the math flags + /// and the math language over `base`), and the run data each object carries. + pub fn paragraph(nodes: &[Math], base: &crate::document::Format) -> Paragraph { + let mut style = base.clone(); + style.italic = Some(true); + style.hidden = Some(false); + style.hyperlink = Some(false); + style.math = Some(true); + style.embedded_object = Some(true); + style.font = Some("Cambria Math".into()); + style.language = Some(0x1007f); + let mut runs: Vec<(String, Option)> = Vec::new(); + write_sequence(nodes, &mut runs); + Paragraph::from_runs(runs.into_iter().map(|(text, object)| { + let mut format = style.clone(); + format.math_object = Some(object.unwrap_or(MathObject { + kind: PLAIN_RUN, + arguments: None, + symbols: Vec::new(), + })); + (text, format) + })) + } +} + +/// The object kind OneNote gives runs between objects. +const PLAIN_RUN: u32 = 0x9000_0000; + +fn write_sequence(nodes: &[Math], runs: &mut Vec<(String, Option)>) { + let mut leaf = String::new(); + for node in nodes { + match node { + Math::Identifier(c) => leaf.push(italic(*c)), + Math::Number(n) => leaf.push_str(n), + Math::Operator(c) => leaf.push(*c), + Math::Object { + kind, + symbols, + arguments, + } => { + if !leaf.is_empty() { + runs.push((std::mem::take(&mut leaf), None)); + } + runs.push(( + OBJECT_START.to_string(), + Some(MathObject { + kind: *kind, + arguments: Some(arguments.len() as u32), + symbols: symbols.clone(), + }), + )); + for (index, argument) in arguments.iter().enumerate() { + let before = runs.len(); + write_sequence(argument, runs); + let control = if index + 1 == arguments.len() { + OBJECT_END + } else { + ARGUMENT_SEPARATOR + }; + let object = MathObject { + kind: *kind, + arguments: (index > 0).then_some(index as u32), + symbols: Vec::new(), + }; + let extended = runs.len() > before; + match runs.last_mut() { + Some((text, slot)) if extended && slot.is_none() => { + text.push(control); + *slot = Some(object); + } + _ => runs.push((control.to_string(), Some(object))), + } + } + } + } + } + if !leaf.is_empty() { + runs.push((leaf, None)); + } +} + +/// The equation editor stores Latin letters as mathematical italics. +fn italic(c: char) -> char { + match c { + 'h' => '\u{210e}', + 'A'..='Z' => char::from_u32(0x1d434 + u32::from(c) - u32::from('A')).unwrap(), + 'a'..='z' => char::from_u32(0x1d44e + u32::from(c) - u32::from('a')).unwrap(), + c => c, + } +} diff --git a/crates/onestore/src/page/text.rs b/crates/onestore/src/page/text.rs index e195c578a4717b0bd436842329d1bb215cb95ebd..8cef50349a53ebdfd299447bf4d170fc50c0ca1a 100644 --- a/crates/onestore/src/page/text.rs +++ b/crates/onestore/src/page/text.rs @@ -154,10 +154,12 @@ impl From for crate::Error { } /// A fresh random identity for a new paragraph or text object. +/// A fresh identity with `n` 1: OneNote never stores an object as `{guid},0`, and OneNote +/// 2010 loses outline elements stored that way (corpus/math-edit/native-drop). pub fn new_id() -> Result { Ok(ExGuid { guid: crate::write::fresh_guid().map_err(|_| EditError::Identity)?, - n: 0, + n: 1, }) } diff --git a/crates/onestore/src/page/write.rs b/crates/onestore/src/page/write.rs index 35abf42da6ecd2792374cb28cac9005215e7d432..8c2285ac616c3957dbf7d5a44981a2e8c51f70b2 100644 --- a/crates/onestore/src/page/write.rs +++ b/crates/onestore/src/page/write.rs @@ -1,7 +1,7 @@ //! Publishes an edited page model by lowering the difference from the stored page onto //! the typed writers, then squashing their transactions into one revision per space. -use super::{Image, Ink, Outline, Page, PageObject, PageParagraph, ParagraphContent, Table}; +use super::{Image, Ink, Math, Outline, Page, PageObject, PageParagraph, ParagraphContent, Table}; use crate::{ Error, ExGuid, Insertion, ObjectData, OutlineEdit, ParagraphJoin, ParagraphSplit, PropertySets, RevisionIndex, Store, TextAttribute, TreeEdit, Value, @@ -184,6 +184,48 @@ fn stroke_values(stroke: &super::InkStroke, index: u32, filetime: u64) -> Result ]) } +/// The character-style properties a span format sets; paragraph-level fields stay on the +/// paragraph style. +fn style_values(format: &crate::document::Format) -> Values { + let mut values = Values::new(); + for (id, flag) in [ + (0x08001c04, format.bold), + (0x08001c05, format.italic), + (0x08001c06, format.underline), + (0x08001c07, format.strike), + (0x08001c08, format.superscript), + (0x08001c09, format.subscript), + (0x08001e16, format.hidden), + (0x08001e14, format.hyperlink), + (0x08001e19, format.hyperlink_label), + (0x08003401, format.math), + (0x08001e22, format.embedded_object), + ] { + if let Some(flag) = flag { + values.push((id | (u32::from(flag) << 31), Vec::new())); + } + } + if let Some(font) = &format.font { + values.push((0x1c001c0a, crate::create::string(font))); + } + if let Some(size) = format.font_size { + values.push(( + 0x10001c0b, + ((size * 2.0).round() as u16).to_le_bytes().to_vec(), + )); + } + if let Some(color) = format.color { + values.push((0x14001c0c, color.to_le_bytes().to_vec())); + } + if let Some(highlight) = format.highlight { + values.push((0x14001c0d, highlight.to_le_bytes().to_vec())); + } + if let Some(language) = format.language { + values.push((0x14001c3b, language.to_le_bytes().to_vec())); + } + values +} + fn picture_fixed_fields(stored: &Image, image: &Image) -> Result<(), Error> { if stored.id != image.id || stored.bytes != image.bytes @@ -494,6 +536,7 @@ impl Lowering<'_> { self.split_and_join(&old, &new, &mut placed, &mut consumed)?; self.place(&old, &new, &placed, &page_order)?; self.delete(&old, &new, &consumed)?; + self.edit_equations(&new)?; self.edit_text(&new)?; self.edit_lists(after, &new)?; self.edit_tags(after, &new)?; @@ -1679,6 +1722,125 @@ impl Lowering<'_> { Ok(()) } + /// Rewrites every equation paragraph whose stored text object differs from the model, the + /// way OneNote stores an equation: the linear text, one run per span with a style + /// carrying the span's format, the run-data array naming each run's inline object, and + /// the math language marker on the text object. + fn edit_equations(&mut self, new: &View<'_>) -> Result<(), Error> { + let current = self.current()?; + let current = View::new(¤t)?; + for (id, paragraph) in &new.paragraphs { + let Some(text) = paragraph.text() else { + continue; + }; + if !Math::is_equation(&text.text) { + continue; + } + let stored = current + .text(self.id(*id)) + .ok_or_else(|| invalid("An equation paragraph is missing after placement"))?; + if stored.text == text.text { + continue; + } + let object = stored.id; + if text.text.text().contains('\u{fffc}') { + return Err(invalid("Equations cannot hold embedded objects")); + } + let encoded: Vec = text + .text + .text() + .encode_utf16() + .chain([0]) + .flat_map(u16::to_le_bytes) + .collect(); + let mut ends = Vec::new(); + let mut styles: Vec = Vec::new(); + let mut sets = Vec::new(); + let all_math = text + .text + .spans() + .iter() + .all(|s| s.format.math == Some(true)); + for span in text.text.spans() { + ends.extend(text.text.utf16_offset(span.end)?.to_le_bytes()); + styles.push(style_values(&span.format)); + sets.push(match &span.format.math_object { + Some(object) => { + let mut set = vec![(0x1400344f, object.kind.to_le_bytes().to_vec())]; + if let Some(count) = object.arguments { + set.push((0x14003450, count.to_le_bytes().to_vec())); + } + for (id, symbol) in [0x10003453, 0x10003454, 0x10003455] + .into_iter() + .zip(&object.symbols) + { + let unit = u16::try_from(u32::from(*symbol)) + .map_err(|_| invalid("Math symbols are single UTF-16 units"))?; + set.push((id, unit.to_le_bytes().to_vec())); + } + set + } + None => Vec::new(), + }); + } + ends.truncate(ends.len() - 4); + let has_objects = sets.iter().any(|set| !set.is_empty()); + let modified = crate::create::current_timestamps()?.0.to_le_bytes(); + let space = self.space; + self.apply(|current| { + crate::write::write_revision(current, space, |raw| { + let mut changed = BTreeMap::new(); + let mut target = PropertyObject::from_object(&raw.objects[&object])?; + let mut references = Vec::new(); + let mut created: Vec<(Values, ExGuid)> = Vec::new(); + for values in &styles { + let id = match created.iter().find(|(known, _)| known == values) { + Some((_, id)) => *id, + None => { + let id = ExGuid { + guid: crate::write::fresh_guid()?, + n: 1, + }; + let mut style = PropertyObject { + jcid: 0x12004d, + bytes: crate::create::properties(values)?, + global_ids: std::sync::Arc::new(BTreeMap::from([(0, id.guid)])), + }; + style.reference(id)?; + changed.insert(id, style); + created.push((values.clone(), id)); + id + } + }; + references.extend(target.reference(id)?); + } + target.remove(&[0x1c003498, 0x40003499])?; + target.set(&[ + (0x1c001c22, &encoded), + (0x1c001e12, &ends), + (0x24001e13, &references), + (0x14001d7a, &modified), + ])?; + if has_objects { + target.set_sets(0x40003499, 0x44000811, &sets)?; + } + if all_math { + // The flags and language marker OneNote's equation editor leaves on + // every equation text object. + target.set(&[ + (0x10001cfe, &0x7f_u16.to_le_bytes()), + (0x14001c3e, &1u32.to_le_bytes()), + (0x14001c84, &1u32.to_le_bytes()), + ])?; + } + changed.insert(object, target); + Ok(changed) + }) + })?; + } + Ok(()) + } + fn edit_text(&mut self, new: &View<'_>) -> Result<(), Error> { let current = self.current()?; let current = View::new(¤t)?; diff --git a/crates/onestore/src/write.rs b/crates/onestore/src/write.rs index b3085fcb2c4719e15eacdebfbab7b3d681cbb83a..a63774c575c95c9d6995134c4c40ffea970897cd 100644 --- a/crates/onestore/src/write.rs +++ b/crates/onestore/src/write.rs @@ -782,6 +782,17 @@ pub(crate) fn write_revisions_with_payloads( index.validate_current()?; let changes = edit(&index)?; let mut output = source.to_vec(); + // Native files reserve 1 KiB per transaction-log fragment; a fragment that ends the file + // keeps that room before the first new chunk. + let tail = store.transaction_fragments.last().unwrap().chunk; + let reserved = usize::try_from(tail.offset + tail.length.max(1024) + 32).unwrap(); + if usize::try_from(tail.offset + tail.length) + .unwrap() + .next_multiple_of(8) + >= output.len() + { + output.resize(reserved, 0); + } let mut maximum = store .transaction_fragments .iter() diff --git a/crates/onestore/tests/page_math.rs b/crates/onestore/tests/page_math.rs index bae4c525ecf5c03c0683dcc5225cf6f7343112aa..c62f12b9b596b23eb78a70f9848833a44647f738 100644 --- a/crates/onestore/tests/page_math.rs +++ b/crates/onestore/tests/page_math.rs @@ -8,10 +8,13 @@ use onestore::{ /// MathML (`corpus/m6/native-math-01`). const NATIVE: &[u8] = include_bytes!("../../../corpus/m6/native-math-01/notebook/synthetic.one"); const NATIVE_READ: &str = include_str!("../../../corpus/m6/native-math-01/read/page-000.xml"); +/// Five more expressions typed through the equation editor by `tools/native_math.py`: +/// subscripts, a sub-superscript, parentheses, an integral and a sum with limits. +const EDITOR: &[u8] = include_bytes!("../../../corpus/math-edit/native-editor/notebook/links.one"); +const EDITOR_READ: &str = include_str!("../../../corpus/math-edit/native-editor/read/page-000.xml"); -fn native_mathml() -> Vec { - NATIVE_READ - .split(" Vec { + read.split("').unwrap() + 1..rest.find("").unwrap()]; @@ -30,9 +33,8 @@ fn native_mathml() -> Vec { .collect() } -#[test] -fn native_equations_render_to_the_mathml_onenote_exports() { - let store = Store::parse(NATIVE).unwrap(); +fn rendered_equations(bytes: &[u8], title: &str) -> Vec { + let store = Store::parse(bytes).unwrap(); let index = RevisionIndex::parse(&store).unwrap(); let document = Document::parse(&index).unwrap(); let page = document @@ -40,7 +42,7 @@ fn native_equations_render_to_the_mathml_onenote_exports() { .unwrap() .into_iter() .map(|(space, _)| Page::from_space(&document, space).unwrap()) - .find(|page| page.title == "Equation controls") + .find(|page| page.title == title) .unwrap(); let mut rendered = Vec::new(); for object in &page.objects { @@ -72,5 +74,236 @@ fn native_equations_render_to_the_mathml_onenote_exports() { rendered.push(Math::mathml(&Math::parse(&equation).unwrap())); } } - assert_eq!(rendered, native_mathml()); + rendered +} + +#[test] +fn native_equations_render_to_the_mathml_onenote_exports() { + assert_eq!( + rendered_equations(NATIVE, "Equation controls"), + native_mathml(NATIVE_READ) + ); +} + +#[test] +fn equation_editor_expressions_render_to_the_mathml_onenote_exports() { + assert_eq!( + rendered_equations(EDITOR, "Read about Rust the Rust site"), + native_mathml(EDITOR_READ) + ); +} + +fn object(kind: u32, symbols: &str, arguments: Vec>) -> Math { + Math::Object { + kind, + symbols: symbols.chars().collect(), + arguments, + } +} + +fn built_equations() -> Vec<(Vec, &'static str)> { + vec![ + ( + vec![ + object( + 31, + "^", + vec![vec![Math::Identifier('x')], vec![Math::Number("2".into())]], + ), + Math::Operator('+'), + Math::Number("1".into()), + ], + "x2+1", + ), + ( + vec![object( + 16, + "/", + vec![ + vec![ + Math::Identifier('a'), + Math::Operator('+'), + Math::Identifier('b'), + ], + vec![object( + 31, + "^", + vec![vec![Math::Identifier('c')], vec![Math::Number("2".into())]], + )], + ], + )], + "a+bc2", + ), + ] +} + +#[test] +fn equations_built_from_the_tree_store_the_native_linear_form_and_parse_back() { + for (nodes, mathml) in built_equations() { + let paragraph = Math::paragraph(&nodes, &onestore::document::Format::default()); + assert!(Math::is_equation(¶graph)); + assert_eq!(Math::parse(¶graph).unwrap(), nodes); + assert_eq!(Math::mathml(&nodes), mathml); + } + let paragraph = Math::paragraph(&built_equations()[0].0, &Default::default()); + assert_eq!(paragraph.text(), "\u{fdd0}\u{1d465}\u{fdee}2\u{fdef}+1"); + let kinds: Vec<(Option, Option)> = paragraph + .spans() + .iter() + .map(|s| { + let object = s.format.math_object.as_ref().unwrap(); + (Some(object.kind), object.arguments) + }) + .collect(); + assert_eq!( + kinds, + [ + (Some(31), Some(2)), + (Some(31), None), + (Some(31), Some(1)), + (Some(0x9000_0000), None) + ] + ); +} + +/// `ONESTORE_MATH_EXPORT` names a new directory receiving the candidate for a cold reopen: +/// every native equation copied onto a fresh page, then two built from the tree. +#[test] +fn equations_are_written_and_read_back() { + use onestore::page::{ParagraphContent, TextObject, text::new_id}; + let source = onestore::create_section("math.one", "Equations below", "Author").unwrap(); + let store = Store::parse(&source).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let (space, _) = document.pages().unwrap()[0]; + let before = Page::from_space(&document, space).unwrap(); + let mut after = before.clone(); + let mut expected_mathml = Vec::new(); + let mut paragraphs = Vec::new(); + for (bytes, title, read) in [ + (NATIVE, "Equation controls", NATIVE_READ), + (EDITOR, "Read about Rust the Rust site", EDITOR_READ), + ] { + expected_mathml.extend(native_mathml(read)); + let store = Store::parse(bytes).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let page = document + .pages() + .unwrap() + .into_iter() + .map(|(space, _)| Page::from_space(&document, space).unwrap()) + .find(|page| page.title == title) + .unwrap(); + for object in &page.objects { + let PageObject::Outline(outline) = object else { + continue; + }; + for paragraph in &outline.paragraphs { + if paragraph.text().is_some_and(|t| Math::is_equation(&t.text)) { + paragraphs.push(paragraph.clone()); + } + } + } + } + for (nodes, mathml) in built_equations() { + let mut paragraph = paragraphs[0].clone(); + paragraph.content = ParagraphContent::Text(TextObject { + id: new_id().unwrap(), + date_field: None, + text: Math::paragraph(&nodes, &Default::default()), + tags: Vec::new(), + }); + paragraphs.push(paragraph); + expected_mathml.push(mathml.to_owned()); + } + let outline = after + .objects + .iter_mut() + .find_map(|object| match object { + PageObject::Outline(outline) if !outline.title => Some(outline), + _ => None, + }) + .unwrap(); + for mut paragraph in paragraphs { + paragraph.id = new_id().unwrap(); + paragraph.parent = None; + paragraph.level = 1; + paragraph.lists.clear(); + paragraph.tags.clear(); + paragraph.style = None; + paragraph.collapsed = false; + if let ParagraphContent::Text(text) = &mut paragraph.content { + text.id = new_id().unwrap(); + text.tags.clear(); + // Paragraph-level spacing came from the source page's paragraph style. + let mut at = 0; + text.text = + onestore::page::Paragraph::from_runs(text.text.spans().iter().map(|span| { + let piece = text.text.text()[at..span.end].to_owned(); + at = span.end; + let mut format = span.format.clone(); + format.space_before = None; + format.space_after = None; + format.line_spacing = None; + (piece, format) + })); + } + outline.paragraphs.push(paragraph); + } + let written = onestore::PreparedEdit::page(&source, space, &after, "Math author").unwrap(); + let store = Store::parse(written.as_bytes()).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + let stored = Page::from_space(&document, space).unwrap(); + let mut expected = after.clone(); + expected.title = stored.title.clone(); + let body = |page: &Page| { + page.objects + .iter() + .find_map(|object| match object { + PageObject::Outline(outline) if !outline.title => Some(outline.paragraphs.clone()), + _ => None, + }) + .unwrap() + }; + for (index, (a, b)) in body(&stored).iter().zip(body(&expected)).enumerate() { + if a != &b { + let (ta, tb) = (a.text().unwrap(), b.text().unwrap()); + assert_eq!(ta.text.text(), tb.text.text(), "paragraph {index} text"); + for (sa, sb) in ta.text.spans().iter().zip(tb.text.spans()) { + assert_eq!(sa, sb, "paragraph {index} span"); + } + assert_eq!( + ta.text.spans().len(), + tb.text.spans().len(), + "paragraph {index} spans" + ); + assert_eq!(a, &b, "paragraph {index}"); + } + } + assert_eq!(stored, expected); + assert_eq!( + rendered_equations(written.as_bytes(), &stored.title), + expected_mathml + ); + if let Some(directory) = std::env::var_os("ONESTORE_MATH_EXPORT") { + let directory = std::path::PathBuf::from(directory); + std::fs::create_dir(&directory).unwrap(); + std::fs::write(directory.join("math.one"), written.as_bytes()).unwrap(); + std::fs::write( + directory.join("Open Notebook.onetoc2"), + onestore::create_table_of_contents( + "Open Notebook.onetoc2", + &[("math.one", store.header.file_id)], + ) + .unwrap(), + ) + .unwrap(); + std::fs::write( + directory.join("expected-mathml.json"), + serde_json::to_string_pretty(&expected_mathml).unwrap(), + ) + .unwrap(); + } } diff --git a/tools/native_format.py b/tools/native_format.py index 09d090f1ff7a49946197c829c642e0625c71473e..57e19bd1e9f27aa757a76ccf2e8a3eccbbbd1b27 100644 --- a/tools/native_format.py +++ b/tools/native_format.py @@ -97,7 +97,8 @@ def compare_formats(space, nodes, native): for run in kind['runs']: style = {**base, **({k: v for k, v in space['nodes'][run['format']]['format'].items() if v is not None} if run['format'] else {})} text = source[run['start'] * 2:run['end'] * 2].decode('utf-16-le') - if not style.get('hidden'): + # Hidden runs and equation runs (exported as MathML) have no visible native text. + if not style.get('hidden') and not style.get('math'): actual.extend((char, style) for char in text) if actual and actual[-1][0] == '\r': actual.pop() diff --git a/tools/native_math.py b/tools/native_math.py new file mode 100644 index 0000000000000000000000000000000000000000..749c70f1c3b4076e6a41fe9d14fd4769c72424cb --- /dev/null +++ b/tools/native_math.py @@ -0,0 +1,70 @@ +"""Author equations through OneNote 2010's equation editor on a Rust-written page and capture +the COM read, which exports each equation as MathML: the oracle for `onestore::page::Math`. + +Usage: native_math.py NOTEBOOK_DIR OUTPUT_DIR +""" +import base64 +import json +import sys +from pathlib import Path +import xml.etree.ElementTree as ET + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +import native_runner as runner + +windows = runner.windows + +# Linear-format input, one equation per paragraph; a space builds each expression up. +EQUATIONS = [ + 'a_1+b_2', + '\\sqrt(x+1)', + 'x_i^2', + '(a+b)', + '\\int_0^1 x dx', + '\\sum_(i=1)^n i', +] + + +def interaction(name, output): + lines = [] + for equation in EQUATIONS: + lines.append('Send("!=")') + lines.append('Sleep(600)') + lines.append('SendText("%s")' % equation.replace('"', '""')) + lines.append('Send(" ")') + lines.append('Sleep(600)') + lines.append('Send("{End}")') + lines.append('Sleep(300)') + lines.append('Send("{Enter}")') + lines.append('Sleep(600)') + page = ET.parse(sorted((output / 'read').glob('page-*.xml'))[0]).getroot().attrib['ID'] + script = '''ComObject("OneNote.Application").NavigateTo("PAGE_ID", "", false) +WinWait("ahk_exe ONENOTE.EXE", , 30) +WinActivate("ahk_exe ONENOTE.EXE") +WinWaitActive("ahk_exe ONENOTE.EXE", , 30) +WinMaximize("ahk_exe ONENOTE.EXE") +Sleep(3000) +CoordMode("Mouse", "Screen") +Click(300, 140) +Sleep(500) +Send("{End}") +Sleep(300) +Send("{Enter}") +Sleep(500) +%s +Sleep(2000) +''' % '\n'.join(lines) + script = script.replace('PAGE_ID', page) + (output / 'equations.ahk').write_text(script) + result = windows.do_exec(script, target=name, timeout_ms=180000, shot_delay_ms=1500) + screenshot = result.pop('png_b64', None) + if screenshot: + (output / 'equations.png').write_bytes(base64.b64decode(screenshot)) + (output / 'equations.json').write_text(json.dumps(result, indent=2)) + if result.get('error') or result.get('exit') != 0: + raise RuntimeError(str(result)) + + +if __name__ == '__main__': + notebook, output = Path(sys.argv[1]), Path(sys.argv[2]) + runner.capture(notebook, output, expected_pages=1, collect_notebook=True, interaction=interaction) diff --git a/tools/test_math_edit.py b/tools/test_math_edit.py new file mode 100644 index 0000000000000000000000000000000000000000..2d6866d8e785b558777dfb321b72a8d4b4a2ffa4 --- /dev/null +++ b/tools/test_math_edit.py @@ -0,0 +1,37 @@ +import json +from pathlib import Path +import re +import runpy +import shutil +from tempfile import TemporaryDirectory +import unittest + +ROOT = Path(__file__).resolve().parent.parent +FIXTURE = ROOT / 'corpus/math-edit' +compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare'] + + +def exported_mathml(path): + text = path.read_text(encoding='utf-8-sig') + out = [] + for body in re.findall(r']*>(.*?)', text, re.S): + out.append(re.sub(r'&#(\d+);', lambda m: chr(int(m.group(1))), body)) + return out + + +class MathEditTest(unittest.TestCase): + def test_equation_editor_expressions_export_as_mathml(self): + self.assertEqual(len(exported_mathml(FIXTURE / 'native-editor/read/page-000.xml')), 5) + + def test_rust_written_equations_export_the_expected_mathml(self): + with TemporaryDirectory() as temporary: + read = Path(temporary) / 'read' + shutil.copytree(FIXTURE / 'written/cold/read', read) + compare(FIXTURE / 'written/candidate', read) + expected = json.loads((FIXTURE / 'written/candidate/expected-mathml.json').read_text()) + self.assertEqual(exported_mathml(FIXTURE / 'written/cold/read/page-000.xml'), expected) + self.assertTrue((FIXTURE / 'written/cold/read/page-000.png').exists()) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/verify-document.py b/tools/verify-document.py index 7b723165a7cda25f6e585f5e54fe5cbf7ab25034..567a87e88b2d5f867562a2b3f78b2a2fb4c9920b 100644 --- a/tools/verify-document.py +++ b/tools/verify-document.py @@ -78,8 +78,10 @@ def verify_pdf_black(path, paragraphs): def visible_text(node, space): kind = node['kind'] data = kind['text'].encode('utf-16-le') + # Hidden runs and equation runs (exported as MathML) have no visible native text. text = ''.join(data[run['start'] * 2:run['end'] * 2].decode('utf-16-le') for run in kind['runs'] - if not run['format'] or not space['nodes'][run['format']]['format']['hidden']) + if not run['format'] or not (space['nodes'][run['format']]['format']['hidden'] + or space['nodes'][run['format']]['format']['math'])) return "" if text == "\u00a0" else project_text(text.removesuffix('\r')) @@ -391,8 +393,9 @@ def compare(notebook, native, versions=None, password_file=None): text_ids = [oid for root in roots for oid, n in walk(space, root) if n['kind']['type'] == 'RichText' and not n['kind']['boilerplate']] for text_id, expected_runs in zip(text_ids, native_runs, strict=True): + # Native XML exports equation runs as MathML, not text (tools/test_math_edit.py compares that). observed_runs = [(char, run['link']) for run in resolved_text[sid][rid][text_id] - if not run['format']['hidden'] for char in run['text']] + if not run['format']['hidden'] and not run['format']['math'] for char in run['text']] if observed_runs and observed_runs[-1][0] == '\r': observed_runs.pop() observed_runs = [(projected, link) for char, link in observed_runs for projected in project_text(char)] -- 2.54.0