From 01ad4f75e66b10945b94ccd6f0b9e9f90ea2a166 Mon Sep 17 00:00:00 2001 From: justinsilvestre Date: Mon, 12 Feb 2024 15:09:25 +0100 Subject: [PATCH] Implement readings auto-lookup --- package-lock.json | 580 +++++++++++++++++- package.json | 1 + src/app/prebuild.ts | 213 ++++++- src/app/texts/Passage.ts | 8 +- src/app/texts/[textId]/ChineseWithPopover.tsx | 71 ++- src/app/texts/[textId]/TextPage.tsx | 46 +- src/app/texts/[textId]/punctuation.tsx | 4 +- src/app/texts/files.ts | 5 +- texts/brandt-ch01-1.vocab.tsv | 158 ++--- texts/brandt-ch01-2.vocab.tsv | 40 ++ texts/brandt-ch01-3.vocab.tsv | 21 + texts/brandt-ch02-1.vocab.tsv | 34 + texts/brandt-ch02-2.vocab.tsv | 31 + texts/brandt-ch02-3.vocab.tsv | 25 + texts/brandt-ch03-1.vocab.tsv | 26 + texts/brandt-ch03-2.vocab.tsv | 28 + texts/brandt-ch03-3.vocab.tsv | 21 + texts/brandt-ch04-1.vocab.tsv | 28 + texts/brandt-ch04-2.vocab.tsv | 27 + texts/brandt-ch04-3.passage.md | 2 +- texts/brandt-ch04-3.vocab.tsv | 55 ++ 21 files changed, 1286 insertions(+), 138 deletions(-) create mode 100644 texts/brandt-ch01-2.vocab.tsv create mode 100644 texts/brandt-ch01-3.vocab.tsv create mode 100644 texts/brandt-ch02-1.vocab.tsv create mode 100644 texts/brandt-ch02-2.vocab.tsv create mode 100644 texts/brandt-ch02-3.vocab.tsv create mode 100644 texts/brandt-ch03-1.vocab.tsv create mode 100644 texts/brandt-ch03-2.vocab.tsv create mode 100644 texts/brandt-ch03-3.vocab.tsv create mode 100644 texts/brandt-ch04-1.vocab.tsv create mode 100644 texts/brandt-ch04-2.vocab.tsv create mode 100644 texts/brandt-ch04-3.vocab.tsv diff --git a/package-lock.json b/package-lock.json index 896fe7e..43c7804 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@floating-ui/react": "^0.26.9", + "@silvestre/cjk-unihan": "^0.0.3-0", "markdown-to-jsx": "^7.4.1", "next": "14.1.0", "react": "^18", @@ -512,6 +513,14 @@ "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==", "dev": true }, + "node_modules/@silvestre/cjk-unihan": { + "version": "0.0.3-0", + "resolved": "https://registry.npmjs.org/@silvestre/cjk-unihan/-/cjk-unihan-0.0.3-0.tgz", + "integrity": "sha512-MHWUHwBsCsr9ELNnZDlqIagXJrMcbzhR6XKiLwp11PyjDxzA6VpVMRGrAqq944ZnkW7Q0LrtJwIvU3w+Ikxwxw==", + "dependencies": { + "sqlite3": "^4.0.9" + } + }, "node_modules/@swc/helpers": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", @@ -724,6 +733,11 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -774,7 +788,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -813,6 +826,20 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -1072,8 +1099,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -1088,7 +1114,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1256,11 +1281,24 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1291,8 +1329,17 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/create-require": { "version": "1.1.1", @@ -1355,6 +1402,14 @@ } } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1393,6 +1448,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1402,6 +1462,17 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2216,11 +2287,32 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.3", @@ -2272,6 +2364,69 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -2520,6 +2675,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -2532,6 +2692,17 @@ "node": ">= 0.4" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -2541,6 +2712,14 @@ "node": ">= 4" } }, + "node_modules/ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dependencies": { + "minimatch": "^3.0.4" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2570,7 +2749,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2579,8 +2757,12 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/internal-slot": { "version": "1.0.7", @@ -2731,7 +2913,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -3186,7 +3367,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3198,7 +3378,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3212,11 +3391,43 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mz": { "version": "2.7.0", @@ -3229,6 +3440,11 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -3252,6 +3468,30 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/needle": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/next": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", @@ -3324,12 +3564,83 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "deprecated": "Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future", + "dependencies": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/node-pre-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-pre-gyp/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/node-pre-gyp/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3348,11 +3659,52 @@ "node": ">=0.10.0" } }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "node_modules/npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3480,7 +3832,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -3502,6 +3853,31 @@ "node": ">= 0.8.0" } }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3557,7 +3933,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3792,6 +4167,11 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -3832,6 +4212,28 @@ } ] }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -3870,6 +4272,25 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4047,6 +4468,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -4064,6 +4490,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -4099,6 +4535,11 @@ "node": ">=10" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/set-function-length": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", @@ -4198,6 +4639,16 @@ "node": ">=0.10.0" } }, + "node_modules/sqlite3": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.2.0.tgz", + "integrity": "sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.11.0" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -4206,6 +4657,14 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -4340,7 +4799,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4501,6 +4959,56 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/tar/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/tar/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4791,8 +5299,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", @@ -4891,6 +5398,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -4988,8 +5521,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/yallist": { "version": "4.0.0", diff --git a/package.json b/package.json index f8c8bb6..be44ad8 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@floating-ui/react": "^0.26.9", + "@silvestre/cjk-unihan": "^0.0.3-0", "markdown-to-jsx": "^7.4.1", "next": "14.1.0", "react": "^18", diff --git a/src/app/prebuild.ts b/src/app/prebuild.ts index 969d5fa..fae65bf 100644 --- a/src/app/prebuild.ts +++ b/src/app/prebuild.ts @@ -1,13 +1,16 @@ import { LexiconEntry, + Passage, PassageVocab, VocabEntryPronunciationKey, parsePassage, parsePassageVocabList, + vocabFileColumns, } from "@/app/texts/Passage"; import { getPassageFileContents, getPassageVocabFileContents, + getPassageVocabFilePath, getTextsIds, } from "@/app/texts/files"; import * as fs from "fs"; @@ -18,17 +21,24 @@ import { toEnMatchKeyword, } from "./lexiconEntryEnKeywords"; +// @ts-expect-error no typings +import unihan from "@silvestre/cjk-unihan"; +import { normalizeText } from "./texts/[textId]/punctuation"; + const prebuildDirectoryPath = path.join(process.cwd(), "prebuild"); if (!fs.existsSync(prebuildDirectoryPath)) { fs.mkdirSync(prebuildDirectoryPath); } -const lexicon = aggregateVocabulary(); -const lexiconFilePath = path.join(prebuildDirectoryPath, "lexicon.json"); -fs.writeFileSync(lexiconFilePath, JSON.stringify(lexicon, null, 2)); -console.log(`Wrote lexicon to ${lexiconFilePath}`); -writePassageVocabularyJsons(lexicon); +fillInMissingReadingsInTsvs().then(() => { + const lexicon = aggregateVocabulary(); + const lexiconFilePath = path.join(prebuildDirectoryPath, "lexicon.json"); + fs.writeFileSync(lexiconFilePath, JSON.stringify(lexicon, null, 2)); + console.log(`Wrote lexicon to ${lexiconFilePath}`); + writePassageVocabularyJsons(lexicon); + console.log(`Done writing vocab jsons`); +}); function aggregateVocabulary() { const textsIds = getTextsIds(); @@ -41,16 +51,137 @@ function aggregateVocabulary() { return lexicon; } +async function fillInMissingReadingsInTsvs() { + let brandtPassagesVisited = 0; + let registeredChars = new Set(); + for (const textId of getTextsIds()) { + const isBrandtPassage = textId.startsWith("brandt-"); + if (isBrandtPassage) brandtPassagesVisited += 1; + const vocabFileContents = getPassageVocabFileContents(textId); + const vocab = parsePassageVocabList(vocabFileContents); + const passage = parsePassage(getPassageFileContents(textId)); + const passageChars = getPassageChars(passage); + + const newCharsInPassage = [...passageChars].filter( + (char) => !registeredChars.has(char) + ); + + if (textId === "brandt-ch01-3") + console.log({ + passageChars: [...passageChars].join(" "), + registeredChars: [...registeredChars].join(" "), + }); + + const featuredChars = new Set( + Object.keys(vocab).concat(isBrandtPassage ? newCharsInPassage : []) + ); + + for (const char of featuredChars) { + if ( + !vocab[char] || + vocab[char]?.some((e) => vocabFileColumns.some((k) => !e[k.key])) + ) { + const unihanResult = await getUnihan(char); + vocab[char] = ( + vocab[char] || [ + { + en: null, + jyutping: null, + kr: null, + pinyin: null, + vi: null, + }, + ] + ).map((e) => ({ + en: e.en || null, + jyutping: + e.jyutping || + unihanResult?.kCantonese + ?.split(/\s/) + .map((r, _, segments) => + segments.length > 1 + ? `${convertToneNumbersToSuperscript(r)}?` + : convertToneNumbersToSuperscript(r) + ) + + .join(", ") || + null, + pinyin: + e.pinyin || + getMandarinReadings(char, unihanResult) + .map((r, _, segments) => (segments.length > 1 ? `${r}?` : r)) + .join(", ") || + null, + vi: + e.vi || + unihanResult?.kVietnamese + ?.split(/\s/) + .map((r, _, segments) => (segments.length > 1 ? `${r}?` : r)) + .join(", ") || + null, + kr: + e.kr || + unihanResult?.kHangul + ?.split(/\s/) + .map((r) => r.split(":")[0]) + .map((r, _, segments) => (segments.length > 1 ? `${r}?` : r)) + .join(", ") || + null, + })); + } + } + + const newVocabFileContents = makeVocabTsvContent(vocab); + + if ( + Object.keys(vocab).length && + newVocabFileContents !== vocabFileContents + ) { + const vocabFilePath = getPassageVocabFilePath(textId); + fs.writeFileSync(vocabFilePath, newVocabFileContents); + if (fs.existsSync(vocabFilePath)) + console.log(`Overwrote file ${vocabFilePath}`); + else console.log(`Created new file ${vocabFilePath}`); + } + + if (isBrandtPassage) + for (const char of passageChars) { + registeredChars.add(char); + } + } +} + +function getPassageChars(passage: Passage) { + const frontmatterZi = getEmbeddedChineseSegments( + passage.frontmatter.description + ).join(""); + + return new Set( + frontmatterZi + + passage.lines.map((l) => normalizeText(l.chinese)).join("") + + Object.values(passage.notes) + .flatMap((n) => getEmbeddedChineseSegments(n)) + .join("") + ); +} + +function getEmbeddedChineseSegments(text: string) { + return [...text.matchAll(/(?<=`)[^`\s\n]+(?=`)/g)].map((t) => + normalizeText(t[0]) + ); +} + function writePassageVocabularyJsons(lexicon: PassageVocab) { for (const textId of getTextsIds()) { - const vocab = parsePassageVocabList(getPassageVocabFileContents(textId)); + const vocabFileContents = getPassageVocabFileContents(textId); + const vocab = parsePassageVocabList(vocabFileContents); const passage = parsePassage(getPassageFileContents(textId)); - const vocabFilePath = path.join( + const vocabJsonPath = path.join( prebuildDirectoryPath, `${textId}.vocab.json` ); - const passageChars = new Set(passage.lines.map((l) => l.chinese).join("")); + const passageChars = getPassageChars(passage); for (const char of passageChars) { if (!vocab[char]) { @@ -58,11 +189,38 @@ function writePassageVocabularyJsons(lexicon: PassageVocab) { } } - fs.writeFileSync(vocabFilePath, JSON.stringify(vocab, null, 2), "utf-8"); - console.log(`Wrote vocab for ${textId} to ${vocabFilePath}`); + fs.writeFileSync(vocabJsonPath, JSON.stringify(vocab, null, 2), "utf-8"); + console.log(`Wrote vocab for ${textId} to ${vocabJsonPath}`); } } +function getMandarinReadings( + char: string, + unihanResult: Partial> +) { + const kMandarin = unihanResult?.kMandarin?.split(/\s/); + if (kMandarin?.length) return kMandarin; + const kHanyuPinyin = + unihanResult?.kHanyuPinyin + ?.split(/\s/) + .flatMap((s) => s.split(":")[1]?.split(",") || s) || []; + return kHanyuPinyin; +} + +function makeVocabTsvContent( + vocab: Partial> +): string | NodeJS.ArrayBufferView { + return [ + `Traditional\tHanyu Pinyin\tJyutping\tKorean\tVietnamese\tEnglish`, + ...Object.entries(vocab).flatMap( + ([char, ee]) => + ee?.map((e) => + [char, e.pinyin, e.jyutping, e.kr, e.vi, e.en].join("\t") + ) || [] + ), + ].join("\n"); +} + function mergeVocab(a: PassageVocab, b: PassageVocab): PassageVocab { const merged: PassageVocab = { ...a }; for (const chinese in b) { @@ -155,3 +313,38 @@ function mergeEntryPronunciation( const mergedSegments = [...new Set([...aSegments, ...bSegments])].join(","); return mergedSegments; } + +async function getUnihan( + char: string +): Promise>> { + return new Promise((res, rej) => { + unihan.get(char, (err: any, result: any) => { + if (err) rej(err); + else { + for (const key in result) { + if (!result[key]) delete result[key]; + } + res(result); + } + }); + }); +} + +const SUPERSCRIPT_NUMBERS = { + "0": "⁰", + "1": "¹", + "2": "²", + "3": "³", + "4": "⁴", + "5": "⁵", + "6": "⁶", + "7": "⁷", + "8": "⁸", + "9": "⁹", +}; +function convertToneNumbersToSuperscript(string: string) { + return string.replace( + /([0-9])$/, + (match, p1) => SUPERSCRIPT_NUMBERS[p1 as keyof typeof SUPERSCRIPT_NUMBERS] + ); +} diff --git a/src/app/texts/Passage.ts b/src/app/texts/Passage.ts index 8fbfd14..bd2aed4 100644 --- a/src/app/texts/Passage.ts +++ b/src/app/texts/Passage.ts @@ -14,12 +14,18 @@ export type LexiconEntry = Record; export type PassageVocab = Partial>; -export type VocabEntryPronunciationKey = "vi" | "jyutping" | "pinyin" | "en"; +export type VocabEntryPronunciationKey = + | "vi" + | "jyutping" + | "pinyin" + | "en" + | "kr"; export const vocabFileColumns = [ { heading: "Vietnamese", key: "vi" }, { heading: "Jyutping", key: "jyutping" }, { heading: "English", key: "en" }, { heading: "Hanyu Pinyin", key: "pinyin" }, + { heading: "Korean", key: "kr" }, ] as const; export function parsePassageVocabList(vocabFileContents: string | null) { diff --git a/src/app/texts/[textId]/ChineseWithPopover.tsx b/src/app/texts/[textId]/ChineseWithPopover.tsx index fc740aa..cf8d121 100644 --- a/src/app/texts/[textId]/ChineseWithPopover.tsx +++ b/src/app/texts/[textId]/ChineseWithPopover.tsx @@ -5,9 +5,13 @@ import { FloatingFocusManager, FloatingPortal, } from "@floating-ui/react"; -import { PassageVocab } from "../Passage"; +import { + LexiconEntry, + PassageVocab, + VocabEntryPronunciationKey, +} from "../Passage"; import { usePopover } from "./Popover"; -import { useState } from "react"; +import { Suspense, useState } from "react"; import { textIsPunctuation } from "./punctuation"; import { findEntryMatchingEnKeywords, @@ -15,7 +19,7 @@ import { } from "@/app/lexiconEntryEnKeywords"; export type DisplayOptions = { - ruby: null | "en" | "vi" | "jyutping" | "pinyin"; + ruby: null | VocabEntryPronunciationKey; translation: boolean; }; @@ -69,6 +73,7 @@ export function ChineseWithPopover({ displayOptions.ruby! ] : null; + const className = `relative cursor:pointer hover:bg-yellow-400/40`; return ( - {rubyText ? ( - - {char} - - {rubyText} - {!soleEntry && !matchingEntry ? "*" : ""} - - - ) : ( - char - )} + + ); })} @@ -144,7 +147,7 @@ function PopoverDictionaryContent( return (
- {[entry.jyutping, entry.pinyin, entry.vi] + {[entry.jyutping, entry.pinyin, entry.kr, entry.vi] .filter((e) => e) .map((e, i, readings) => ( @@ -200,3 +203,41 @@ function PopoverDictionaryContent( ); } + +function RubyText({ + char, + enGloss, + displayOptions, + soleEntry, + matchingEntry, + firstEntry, +}: { + char: string; + enGloss: string | null; + displayOptions: DisplayOptions; + soleEntry: LexiconEntry | null; + matchingEntry: LexiconEntry | null; + firstEntry: LexiconEntry | null; +}) { + if (typeof window === "undefined") + throw Error("This component is client-only"); + let rubyText: string | undefined | null = null; + if (displayOptions.ruby === "en") rubyText = enGloss; + else + rubyText = + displayOptions?.ruby && (matchingEntry || soleEntry || firstEntry) + ? (matchingEntry || soleEntry || firstEntry)?.[displayOptions.ruby!] + : null; + + return rubyText ? ( + + {char} + + {rubyText} + {!soleEntry && !matchingEntry ? "*" : ""} + + + ) : ( + char + ); +} diff --git a/src/app/texts/[textId]/TextPage.tsx b/src/app/texts/[textId]/TextPage.tsx index 14c549c..ef72bb6 100644 --- a/src/app/texts/[textId]/TextPage.tsx +++ b/src/app/texts/[textId]/TextPage.tsx @@ -4,7 +4,7 @@ import Markdown from "markdown-to-jsx"; import markdownCss from "./markdown.module.css"; import { Passage, PassageVocab } from "../Passage"; import { ChineseWithPopover, DisplayOptions } from "./ChineseWithPopover"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { normalizeText } from "./punctuation"; export default function TextPage({ @@ -15,10 +15,7 @@ export default function TextPage({ vocab: PassageVocab; }) { const notesWithHeadings: { id: string; heading: string }[] = []; - const [displayOptions, setDisplayOptions] = useState({ - ruby: "vi", - translation: true, - }); + const [displayOptions, setDisplayOptions] = useDisplayOptions(); return (
@@ -49,7 +46,7 @@ export default function TextPage({
-
+
+ + setDisplayOptions((opts) => ({ ...opts, ruby: "kr" })) + } + label="Sino-Korean" + /> setDisplayOptions((opts) => ({ ...opts, ruby: "vi" })) } - label="Vietnamese" + label="Sino-Vietnamese" /> + (() => + globalThis.window && localStorage.getItem("displayOptions") + ? JSON.parse(localStorage.getItem("displayOptions") as string) + : { + ruby: "vi", + translation: true, + } + ); + const initialized = useRef(false); + useEffect(() => { + if (!initialized.current) { + const localStorageDisplayOptions = localStorage.getItem("displayOptions"); + if (localStorageDisplayOptions) { + setDisplayOptions(JSON.parse(localStorageDisplayOptions)); + } + initialized.current = true; + } else { + localStorage.setItem("displayOptions", JSON.stringify(displayOptions)); + } + }, [displayOptions]); + + return [displayOptions, setDisplayOptions] as const; +} + function NotesChinese({ children, vocab, diff --git a/src/app/texts/[textId]/punctuation.tsx b/src/app/texts/[textId]/punctuation.tsx index a68c540..189750e 100644 --- a/src/app/texts/[textId]/punctuation.tsx +++ b/src/app/texts/[textId]/punctuation.tsx @@ -1,7 +1,7 @@ const punctuationRegex = - /[。,?!;:、「」『』()《》〈〉﹁﹂﹃﹄【】〔〕]+/; + /[。,?!;:、「」『』()《》〈〉﹁﹂﹃﹄【】〔〕a-zA-Z\s0-9\-:{}\,;\.()]+/; const punctuationRegexG = - /[。,?!;:、「」『』()《》〈〉﹁﹂﹃﹄【】〔〕]+/g; + /[。,?!;:、「」『』()《》〈〉﹁﹂﹃﹄【】〔〕a-zA-Z\s0-9\-:{}\,;\.()]+/g; export function normalizeText(text: string) { return text.replaceAll(punctuationRegexG, ""); diff --git a/src/app/texts/files.ts b/src/app/texts/files.ts index 6646e93..c47eb1a 100644 --- a/src/app/texts/files.ts +++ b/src/app/texts/files.ts @@ -14,8 +14,11 @@ export const getPassageFileContents = (textId: string) => { const passageFilePath = path.resolve(textsDirectory, `${textId}.passage.md`); return fs.readFileSync(passageFilePath, "utf8"); }; + +export const getPassageVocabFilePath = (textId: string) => + path.resolve(textsDirectory, `${textId}.vocab.tsv`); export const getPassageVocabFileContents = (textId: string) => { - const vocabFilePath = path.resolve(textsDirectory, `${textId}.vocab.tsv`); + const vocabFilePath = getPassageVocabFilePath(textId); return fs.existsSync(vocabFilePath) ? fs.readFileSync(vocabFilePath, "utf8") : null; diff --git a/texts/brandt-ch01-1.vocab.tsv b/texts/brandt-ch01-1.vocab.tsv index 7c4ccc7..99518ec 100644 --- a/texts/brandt-ch01-1.vocab.tsv +++ b/texts/brandt-ch01-1.vocab.tsv @@ -1,77 +1,81 @@ -Traditional Vietnamese Jyutping English -吉 cát gat¹ fortunate; prosperous; auspicious -凶 hung hung¹ unfortunate; unlucky; cruel -有 hữu jau⁵ to have; to exist; to be -鴉 nha aa¹ a crow; a raven -集 tập zaap⁶ to flock together; to collect; to compile -庭 đình ting⁴ the audience hall; a courtyard; a room; a house -樹 thụ syu⁶ a tree; to set up; to erect -引 dẫn jan⁵ to draw out; to stretch; to prolong; to lead, to quote -頸 cảnh geng² the neck; the throat; an isthmus -而 nhi ji⁴ a conjunctive particle; an adversative particle; and; yet; but; like; you; your -鳴 minh ming⁴ the cry of a bird or animal; a sound; to sing; to cry -兒 nhi ji⁴ a child; a son; male; boy -叱 sất cik¹ to hoot at -之 chi zi¹ of; it; him; her; them; this; that; to go; to proceed -父 phụ fu⁶ a father -曰 viết joek⁶ to speak -是 thị si⁶ to be; right; this; that -何 hà ho⁴ an interrogative particle; how; why; what -害 hại hoi⁶ to injure; harm -常 thường soeng⁴ constant; usual; frequent -聞 văn man⁴ to hear; to smell; read -聞 vấn man⁴, man² to make known; to state -人 nhân jan⁴ a man; person -言 ngôn jin⁴ words; language; to speak; to express; to say -鵲 thước coek³ the magpie; the jay -今 kim gam¹ now; the present time -者 giả ze² a particle of many uses imparting various shades of meaning - adjectival, participial etc. to words to which it is joined; that which -也 dã jaa⁵ a final particle -故 cố gu³ a consequential particle; cause; reason; therefore; a causal particle -智 trí zi³ wisdom; knowledge -識 thức sik¹ to know; to be acquainted with -智識 trí thức zi³ sik¹ knowledge and experience -遠 viễn jyun⁵ far off; distant; remote -勝 thắng sing³ to conquer; to excel -勝 thăng sing¹ to be adequate to; to be worthy of -於 ư jyu¹ in; at; on; for; among; by; than -鳥 điểu niu⁵ a bird -尚 thượng soeng⁶ to wish; to esteem; to add; still -不 bất bat¹ not -能 năng nang⁴ to be able; to be competent; ability -預 dự jyu⁶ pleased; satisfied; to be ready; beforehand -知 tri zi¹ to know; to perceive; to be aware of -況 huống fong³ moreover; still more; how much more -而況 nhi huống ji⁴ fong³ still more; how much more -乎 hồ fu⁴ an interrogative particle; an exclamatory particle; an expletive -背 bội bui³ behind; contrary -理 lý lei⁵ right -行 hành hang⁴ to act; to do -思 tư si¹ to think -得 đắc dak¹ to get; to receive -嚴 nghiêm jim⁴ severe -治 trị zi⁶ to govern -如 như jyu⁴ like; as -不如 bất như bat¹ jyu⁴ not equal, worse -好 hiếu hou³ to love; to like -德 đức dak¹ virtue -必 tất bit¹ certainly; must -其 kỳ kei⁴ it -仁 nhân jan⁴ benevolent -我 ngã ngo⁵ me -信 tín seon³ to believe -學 học hok⁶ learn -祿 lộc luk⁶ salary -在 tại zoi⁶ in -中 trung zung¹ middle; within -矣 hỹ ji⁵ a final particle -耕 canh gaang¹ to plough -餒 nỗi neoi⁵ hunger -莫 mạc mok⁶ not; there is not -大 đại daai⁶ big; great -天 thiên tin¹ heaven; God -水 thủy seoi² water -高 cao gou¹ high -岸 ngạn ngon⁶ shore bank -貴 quý gwai³ dear; honorable -銀 ngân ngan⁴ silver \ No newline at end of file +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +吉 jí gat¹ 길 cát fortunate; prosperous; auspicious +凶 xiōng hung¹ 흉 hung unfortunate; unlucky; cruel +有 yǒu jau⁵ 유 hữu to have; to exist; to be +鴉 yā aa¹ 아 nha a crow; a raven +集 jí zaap⁶ 집 tập to flock together; to collect; to compile +庭 tíng ting⁴ 정 đình the audience hall; a courtyard; a room; a house +樹 shù syu⁶ 수 thụ a tree; to set up; to erect +引 yǐn jan⁵ 인 dẫn to draw out; to stretch; to prolong; to lead, to quote +頸 jǐng geng² 경 cảnh the neck; the throat; an isthmus +而 ér ji⁴ 이 nhi a conjunctive particle; an adversative particle; and; yet; but; like; you; your +鳴 míng ming⁴ 명 minh the cry of a bird or animal; a sound; to sing; to cry +兒 ér ji⁴ 아?, 예? nhi a child; a son; male; boy +叱 chì cik¹ 질 sất to hoot at +之 zhī zi¹ 지 chi of; it; him; her; them; this; that; to go; to proceed +父 fù fu⁶ 부 phụ a father +曰 yuē joek⁶ 왈 viết to speak +是 shì si⁶ 시 thị to be; right; this; that +何 hé ho⁴ 하 hà an interrogative particle; how; why; what +害 hài hoi⁶ 해 hại to injure; harm +常 cháng soeng⁴ 상 thường constant; usual; frequent +聞 wén man⁴ 문 văn to hear; to smell; read +聞 wèn man⁴, man² 문 vấn to make known; to state +人 rén jan⁴ 인 nhân a man; person +言 yán jin⁴ 언 ngôn words; language; to speak; to express; to say +鵲 què coek³ 작 thước the magpie; the jay +今 jīn gam¹ 금 kim now; the present time +者 zhě ze² 자 giả a particle of many uses imparting various shades of meaning - adjectival, participial etc. to words to which it is joined; that which +也 yě jaa⁵ 야 dã a final particle +故 gù gu³ 고 cố a consequential particle; cause; reason; therefore; a causal particle +智 zhì zi³ 지 trí wisdom; knowledge +識 shí?, shì sik¹ 식?, 지? thức to know; to be acquainted with +智識 zi³ sik¹ trí thức knowledge and experience +遠 yuǎn jyun⁵ 원 viễn far off; distant; remote +勝 shèng sing³ 승 thắng to conquer; to excel +勝 shèng sing¹ 승 thăng to be adequate to; to be worthy of +於 yú jyu¹ 어 ư in; at; on; for; among; by; than +鳥 niǎo niu⁵ 조 điểu a bird +尚 shàng soeng⁶ thượng to wish; to esteem; to add; still +不 bù bat¹ 부?, 불? bất not +能 néng nang⁴ 능 năng to be able; to be competent; ability +預 yù jyu⁶ 예 dự pleased; satisfied; to be ready; beforehand +知 zhī zi¹ 지 tri to know; to perceive; to be aware of +況 kuàng fong³ 황 huống moreover; still more; how much more +而況 ji⁴ fong³ nhi huống still more; how much more +乎 hū fu⁴ 호 hồ an interrogative particle; an exclamatory particle; an expletive +背 bèi bui³ 배 bội behind; contrary +理 lǐ lei⁵ 리?, 이? lý right +行 xíng hang⁴ 항?, 행? hành to act; to do +思 sī si¹ 사 tư to think +得 dé dak¹ 득 đắc to get; to receive +嚴 yán jim⁴ 엄 nghiêm severe +治 zhì zi⁶ 치 trị to govern +如 rú jyu⁴ 여 như like; as +不如 bat¹ jyu⁴ bất như not equal, worse +好 hǎo hou³ 호 hiếu to love; to like +德 dé dak¹ 덕 đức virtue +必 bì bit¹ 필 tất certainly; must +其 qí kei⁴ 기 kỳ it +仁 rén jan⁴ 인 nhân benevolent +我 wǒ ngo⁵ 아 ngã me +信 xìn seon³ 신 tín to believe +學 xué hok⁶ 학 học learn +祿 lù luk⁶ 녹?, 록? lộc salary +在 zài zoi⁶ 재 tại in +中 zhōng zung¹ 중 trung middle; within +矣 yǐ ji⁵ 의 hỹ a final particle +耕 gēng gaang¹ 경 canh to plough +餒 něi neoi⁵ 뇌 nỗi hunger +莫 mò mok⁶ 막 mạc not; there is not +大 dà daai⁶ 대 đại big; great +天 tiān tin¹ 천 thiên heaven; God +水 shuǐ seoi² 수 thủy water +高 gāo gou¹ 고 cao high +岸 àn ngon⁶ 안 ngạn shore bank +貴 guì gwai³ 귀 quý dear; honorable +銀 yín ngan⁴ 은 ngân silver +聚 jù zeoi⁶ 취 tụ +院 yuàn jyun² 원 viện +內 nèi noi⁶ 내 +上 shàng soeng⁶ 상 thượng \ No newline at end of file diff --git a/texts/brandt-ch01-2.vocab.tsv b/texts/brandt-ch01-2.vocab.tsv new file mode 100644 index 0000000..e896d3d --- /dev/null +++ b/texts/brandt-ch01-2.vocab.tsv @@ -0,0 +1,40 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +影 yǐng jing² 영 ảnh +新 xīn san¹ 신 tân +月 yuè jyut⁶ 월 nguyệt +初 chū co¹ 초 sơ +廊 láng long⁴ 낭?, 랑? lang +下 xià haa⁶ 하 hạ +似 shì ci⁵ 사 tự +一 yī jat¹ 일 nhất +隨 suí ceoi⁴ 수 tuỳ +後 hòu hau⁶ 후 hậu +敢 gǎn gam² 감 cám +回 huí wui⁴ 회 hồi +顧 gù gu³ 고 cố +急 jí gap¹ 급 cấp +入 rù jap⁶ 입 nhập +告 gào gou³ 고 +姊 zǐ zi² 자 chị +此 cǐ ci² 차 thử +汝 rǔ jyu⁵ 여 nhớ +身 shēn san¹ 신 thân +立 lì lap⁶ 립?, 입? lập +燈 dēng dang¹ 등 đăng +前 qián cin⁴ 전 tiền +日 rì jat⁶ 일 nhật +皆 jiē gaai¹ 개 giai +忘 wàng mong⁴ 망 vong +耶 yé je⁴ 야 +乃 nǎi naai⁵ 내 nải +悟 wù ng⁶ 오 +可 kě ho² 가 khả +老 lǎo lou⁵ 노?, 로? lão +少 shǎo siu² 소 thiểu +四 sì sei³ 사 tứ +海 hǎi hoi² 해 hải +兄 xiōng hing¹ 형 huynh +弟 dì dai⁶ 제 đệ +百 bǎi baak³ 백 vầu?, bách? +事 shì si⁶ 사 sự +遂 suì seoi⁶ 수 toại \ No newline at end of file diff --git a/texts/brandt-ch01-3.vocab.tsv b/texts/brandt-ch01-3.vocab.tsv new file mode 100644 index 0000000..0ef57a3 --- /dev/null +++ b/texts/brandt-ch01-3.vocab.tsv @@ -0,0 +1,21 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +多 duō do¹ 다 đa +無 wú mou⁴ 무 vô +益 yì jik¹ 익 ích +或 huò waak⁶ 혹 hoặc +問 wèn man⁶ 문 +墨 mò mak⁶ 묵 +子 zi zi² 자 tí +以 yǐ ji⁵ 이 +爲 wèi wai⁴ 위 vay +蝦 xiā haa¹ 하 +蟆 má maa⁴ +夜 yè je⁶ 야 dạ +厭 yàn jim³ 염 ướm +雄 xióng hung⁴ 웅 hùng +鷄 jī gai¹ 계 +振 zhèn zan³ 진 chấn +動 dòng dung⁶ 동 động +當 dāng dong¹ 당 đương +時 shí si⁴ 시 thì +已 yǐ ji⁵ 이 dĩ \ No newline at end of file diff --git a/texts/brandt-ch02-1.vocab.tsv b/texts/brandt-ch02-1.vocab.tsv new file mode 100644 index 0000000..ba09190 --- /dev/null +++ b/texts/brandt-ch02-1.vocab.tsv @@ -0,0 +1,34 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +字 zì zi⁶ 자 tự +山 shān saan¹ 산 sơn +虎 hǔ fu² 호 hổ +畜 chù cuk¹ 축 chuỗi?, súc? +獵 liè lip⁶ 렵?, 엽? lốp +謀 móu mau⁴ 모 mưu +捕 bǔ bou⁶ 포 bõ +設 shè cit³ 설 thết +阱 jǐng zing⁶ +伺 cì zi⁶ 사 +書 shū syu¹ 서 thư +牆 qiáng coeng⁴ 장 teo?, tường? +止 zhǐ zi² 지 chỉ +步 bù bou⁶ 보 bộ +鄉 xiāng hoeng¹ +過 guò gwo³ 과 quá +誤 wù ng⁶ 오 +蹴 cù cuk¹ 축 +墜 zhuì zeoi⁶ 추 truỵ +傷 shāng soeng¹ 상 thương +足 zú zuk¹ 족 túc +呼 hū fu¹ 호 hô +求 qiú kau⁴ 구 cầu +援 yuán wun⁴ 원 viện +旣 jì gei³ 기 +出 chū ceot¹ 출 xuất +指 zhǐ zi² 지 chỉ +嘆 tàn taan³ 탄 han +吾 wú ng⁴ 오 ngo +苟 gǒu gau² 구 +豈 qǐ hei² 개?, 기? +至 zhì zi³ 지 chí +哉 zāi zoi¹ 재 tai \ No newline at end of file diff --git a/texts/brandt-ch02-2.vocab.tsv b/texts/brandt-ch02-2.vocab.tsv new file mode 100644 index 0000000..6e432f8 --- /dev/null +++ b/texts/brandt-ch02-2.vocab.tsv @@ -0,0 +1,31 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +老 lǎo lou⁵ 노?, 로? lão +渴 kě hot³ 갈 khát +甚 shén sam⁶ 심 thậm +見 jiàn gin³ 견?, 현? kiến +壺 hú wu⁴ 호 +欲 yù juk⁶ 욕 dục +飲 yǐn jam² ẩm +深 shēn sam¹ 심 thâm +竭 jié kit³ 갈 kiệt +力 lì lik⁶ 력?, 역? lực +伸 shēn san¹ 신 +喙 huì fui³ 훼 +卒 zú zeot¹ 졸 tốt +仰 yǎng joeng⁵ 앙 ngưỡng +首 shǒu sau² 수 thủ +若 ruò joek⁶ 야?, 약? nhược +忽 hū fat¹ 홀 hốt +飛 fēi fei¹ 비 phi +去 qù heoi³ 거 khứ +銜 xián haam⁴ 함 +石 shí sek⁶ 석 thạch +投 tóu tau⁴ 투 đầu +往 wǎng wong⁵ 왕 vãng +返 fǎn faan² 반 phản +十 shí sap⁶ 십 thập +餘 yú jyu⁴ 여 dư +次 cì ci³ 차 thứ +積 jī zik¹ 적 tích +升 shēng sing¹ 승 thăng +谒 yè jit³ \ No newline at end of file diff --git a/texts/brandt-ch02-3.vocab.tsv b/texts/brandt-ch02-3.vocab.tsv new file mode 100644 index 0000000..f4a7523 --- /dev/null +++ b/texts/brandt-ch02-3.vocab.tsv @@ -0,0 +1,25 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +卜 bo?, bǔ? baak⁶ 복 bốc +坐 zuò zo⁶ 좌 +四 sì sei³ 사 tứ +達 dá daat⁶ 달 đạt +衢 qú keoi⁴ 구 +語 yǔ jyu⁵ 어 ngữ +休 xiū jau¹ 휴 hưu +咎 jiù gau³ 구 +奔 bēn ban¹ 분 +家 jiā gaa¹ 가 gia +所 suǒ so² 소 sỡ +刧 jié gip³ 겁 kiếp +具 jù geoi⁶ 구 cụ +盡 jǐn zeon⁶ 진 tận +喪 sàng song¹ 상 tang +倉 cāng cong¹ 창 +惶 huáng wong⁴ 황 hoàng +失 shī sat¹ 실 thất +措 cuò cou³ 조 thố +調 diào diu⁶ 조?, 주? điều +君 jūn gwan¹ 군 quân +兆 zhào siu⁶ 조 triệu +省 shěng saang² 생?, 성? tỉnh +對 duì deoi³ 대 đỗi \ No newline at end of file diff --git a/texts/brandt-ch03-1.vocab.tsv b/texts/brandt-ch03-1.vocab.tsv new file mode 100644 index 0000000..a7aa4ce --- /dev/null +++ b/texts/brandt-ch03-1.vocab.tsv @@ -0,0 +1,26 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +五 wǔ ng⁵ 오 ngũ +田 tián tin⁴ 전 điền +饒 ráo jiu⁴ 요 nhiêu +謂 wèi wai⁶ 위 +魯 lǔ lou⁵ 노?, 로? lỗ +哀 āi oi¹ 애 ai +公 gōng gung¹ 공 công +夫 fū fu¹ 부 phu +頭 tóu tau⁴ 두 đầu +戴 dài daai³ 대 +冠 guān gun¹ 관 quán +文 wén man⁴ 문 văn +撐 chēng caang¹ 탱 +距 jù keoi⁵ 거 cựa +武 wǔ mou⁵ 무 vũ +敵 dí dik⁶ 적 địch +鬭 dòu dau³ đấu +勇 yǒng jung⁵ 용 dũng +食 shí sik⁶ 식 +相 xiāng soeng¹ 상 tương +義 yì ji⁶ 의 nghĩa +司 sī si¹ 사 ti +晨 chén san⁴ 신 thần +實 shí sat⁶ 실?, 지? thực +覯 gòu gau³ 구 \ No newline at end of file diff --git a/texts/brandt-ch03-2.vocab.tsv b/texts/brandt-ch03-2.vocab.tsv new file mode 100644 index 0000000..28e093a --- /dev/null +++ b/texts/brandt-ch03-2.vocab.tsv @@ -0,0 +1,28 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +仲 zhòng zung⁶ 중 +齊 qí cai⁴ 제 tày +居 jū geoi¹ 거 cư +士 shì si⁶ 사 sĩ +王 wáng wong⁴ 왕 vương +養 yǎng joeng⁵ 양 dưỡng +厚 hòu hau⁵ 후 +責 zé zaak³ 채?, 책? trách +事 shì si⁶ 사 sự +安 ān on¹ 안 an +屈 qū wat¹ 굴 khuất +榖 gǔ guk¹ kéo?, cốc? +匏 páo paau⁴ 포 bầu +堅 jiān gin¹ 견 kiên +竅 qiào kiu³ 규 khíu +願 yuàn jyun⁶ 원 nguyện +獻 xiàn hin³ 헌 hiến +盛 shèng sing⁶ 성 thịnh +則 zé zak¹ 칙 tắc +剖 pōu?, pǒ? fau² 부 bo +物 wù mat⁶ 물 vật +用 yòng jung⁶ 용 dụng +穀 gǔ guk¹ 곡 +亦 yì jik⁶ 역 +國 guó gwok³ 국 quốc +殆 dài toi⁵ 태 +類 lèi leoi⁶ 류?, 유? loại \ No newline at end of file diff --git a/texts/brandt-ch03-3.vocab.tsv b/texts/brandt-ch03-3.vocab.tsv new file mode 100644 index 0000000..9ccf5ba --- /dev/null +++ b/texts/brandt-ch03-3.vocab.tsv @@ -0,0 +1,21 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +愈 yù jyu⁶ 유 rủ +久 jiǔ gau² 구 cửu +加 jiā gaa¹ 가 gia +速 sù cuk¹ 속 tốc +妙 miào miu⁶ 묘 diệu +更 gèng gang¹ 갱?, 경? xâu?, canh? +要 yào jiu³ 요 yếu +件 jiàn gin⁶ 건 kiện +善 shàn sin⁶ 선 thiện +尤 yóu jau⁴ 우 +異 yì ji⁶ 리?, 이? +怪 guài gwaai³ 괴 +緊 jǐn gan² 긴 khẩn +觀 guān gun¹ 관 quan +虚 xū heoi¹ hư +分 fēn fan¹ 분 phân +量 liàng loeng⁴ 량?, 양? +等 děng dang² 등 đẳng +平 píng ping⁴ 평 bình +低 dī dai¹ 저 đây \ No newline at end of file diff --git a/texts/brandt-ch04-1.vocab.tsv b/texts/brandt-ch04-1.vocab.tsv new file mode 100644 index 0000000..d1874b1 --- /dev/null +++ b/texts/brandt-ch04-1.vocab.tsv @@ -0,0 +1,28 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +海 hǎi hoi² 해 hải +魚 yú jyu⁴ 어 ngư +靖 jìng zing⁶ 정 +郭 guō gwok³ 곽 quách +封 fēng fung¹ 봉 phong +薛 xuē sit³ 설 +將 jiāng zoeng¹ 장 tướng +城 chéng sing⁴ 성 thành +客 kè haak³ 객 khách +諫 jiàn gaan³ 간 gián +網 wǎng mong⁵ 망 võng +鈎 gōu ngau¹ +牽 qiān hin¹ 견 +幸 xìng hang⁶ 행 +螻 lóu lau⁴ 루 sâu +蟻 yǐ ngai⁵ 의 +制 zhì zai³ 제 chế +焉 yān jin¹ 언 vờn +猶 yóu jau⁴ 유 +强 qiáng koeng⁴ 강 +又 yòu jau⁶ 우 lại +憂 yōu jau¹ 우 ưu +旦 dàn daan³ 단 đán +亡 wáng mong⁴ 망 vong +雖 suī seoi¹ 수 tuy +築 zhú zuk¹ 축 trốc +使 shǐ si² 사 sứ \ No newline at end of file diff --git a/texts/brandt-ch04-2.vocab.tsv b/texts/brandt-ch04-2.vocab.tsv new file mode 100644 index 0000000..d192349 --- /dev/null +++ b/texts/brandt-ch04-2.vocab.tsv @@ -0,0 +1,27 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +爭 zhēng zaang¹ 쟁 tranh +賃 lìn jam⁶ 임 +驢 lǘ lou⁴ 려 lừa +方 fāng fong¹ 방 phương +暑 shǔ syu² 서 +覓 mì mik⁶ 멱 +蔭 yīn jam¹ 음 ấm +伏 fú fuk⁶ 복 phục +腹 fù fuk¹ 복 phục +避 bì bei⁶ 피 tị +然 rán jin⁴ 연 nhiên +僅 jǐn gan² 근 +蔽 bì bai³ 폐 +與 yǔ jyu⁵ 여 dữ +錢 qián cin⁴ 전 tiền +屬 shǔ suk⁶ 속 thuộc +讓 ràng joeng⁶ 양 nhường +鬪 dòu dau³ 투 đấu +驚 jīng ging¹ 경 kinh +逸 yì jat⁶ 일 dật +共 gòng gung⁶ 공 cộng +追 zhuī zeoi¹ 추 truy +獲 huò wok⁶ 획 hoạch +懊 ào ou³ 오 ảo +歸 guī gwai¹ 귀 +虛 xū heoi¹ 허 \ No newline at end of file diff --git a/texts/brandt-ch04-3.passage.md b/texts/brandt-ch04-3.passage.md index 177ce72..931f26f 100644 --- a/texts/brandt-ch04-3.passage.md +++ b/texts/brandt-ch04-3.passage.md @@ -61,7 +61,7 @@ These particles are: 15 各省教案同時並起 15 - Missionary cases occurred in all the provinces at the same time. -16 一切兵器槪屬違禁。不准販運 +16 一切兵器概屬違禁。不准販運 16 - Weapons of war of every kind are contraband,and trade in them is not allowed. 17 萬邦咸寕 diff --git a/texts/brandt-ch04-3.vocab.tsv b/texts/brandt-ch04-3.vocab.tsv new file mode 100644 index 0000000..4a0b442 --- /dev/null +++ b/texts/brandt-ch04-3.vocab.tsv @@ -0,0 +1,55 @@ +Traditional Hanyu Pinyin Jyutping Korean Vietnamese English +内 nèi noi⁶ nội +兄 xiōng hing¹ 형 huynh +弟 dì dai⁶ 제 đệ +寸 cùn cyun³ 촌 thốn +土 tǔ tou² 토 thổ +地 de?, dì? dei⁶ 지 địa +少 shǎo siu² 소 thiểu +自 zì zi⁶ 자 tự +古 gǔ gu² 고 cổ +死 sǐ sei² 사 phơi?, tử? +各 gè gok³ 각 các +商 shāng soeng¹ 상 thương +均 jūn gwan¹ 균?, 연? quân +禾 hé wo⁴ 화 +遭 zāo zou¹ 조 tao +淹 yān jim¹ 엄 êm +沒 méi mut⁶ 몰 mớ?, một? +生 shēng sang¹ 생 sinh +意 yì ji³ 의 ý +來 lái loi⁴ 내?, 래? lai +買 mǎi maai⁵ 매 mãi +賣 mài maai⁶ 매 mại +泰 tài taai³ 태 thái +西 xī sai¹ 서 tây +俱 jù keoi¹ 구 câu +例 lì lai⁶ 례?, 예? lề +民 mín man⁴ 민 dân +教 jiào gaau³ 교 giáo +苗 miáo miu⁴ 묘 meo +晝 zhòu zau³ 주 +等 děng dang² 등 đẳng +長 zhǎng coeng⁴ 장 trường +並 bìng bing⁶ 병 +重 zhòng cung⁵ 중 trọng +案 àn on³ 안 duyên?, án? +同 tóng tung⁴ 동 đồng +起 qǐ hei² 기 khởi +切 qiè cit³ 절?, 체? thiết +兵 bīng bing¹ 병 binh +器 qì hei³ 기 khí +概 gài koi³ +違 wéi wai⁴ 위 vi +禁 jìn gam³ 금 cấm +准 zhǔn zeon² 준 chốn +販 fàn faan³ 판 +運 yùn wan⁶ 운 vận +萬 wàn maan⁶ 만 vạn +邦 bāng bong¹ 방 vâng +咸 xián haam⁴ 함 +寕 níng ning⁴ +幼 yòu jau³ 유 ấu +悉 xī sik¹ 실 tạt +聽 tīng ting¹ 청 thính +肸 xī jat⁶ \ No newline at end of file