From 6ff2ed99ece57de7a868baa34da7bb148ad289ae Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 13 Aug 2026 11:27:01 +0700 Subject: [PATCH] refactor: collapse the two projects into one tree and move to npm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo held two near-duplicate projects. 2016/ and 2017/ each carried their own React frontend, their own copy of the same Rust crate, and their own package manager setup. 2016/tools/sync-from-thptqg2017.sh existed purely to copy the parser source between them. New layout: index.html + src/ the 2017 frontend, now the only one data// 2016, 2017, 2017-old, 2017-old2 parser/ the single Rust crate, configs renamed to .toml docs/ both projects' docs, 2016 copies suffixed -2016-legacy pending the merge pass is now one identifier end to end: data// feeds parser/configs/.toml and produces db/.db.gz. pnpm gives way to npm. pnpm-workspace.yaml existed only to whitelist better-sqlite3's native build, which npm permits by default, so it has no equivalent and is simply gone. Lockfiles cannot be converted; package-lock.json is generated fresh. The migration direction is safe — pnpm's strict layout forbids phantom dependencies, so anything that resolved under pnpm resolves under npm's flat tree. Adds parser/scripts/build-db.js and src/datasets.js: the four dataset IDs are declared once and read by both the build tooling and (from the next phase) the frontend. Follow-on fixes the move made necessary: - eslint's Node-globals override pointed at scripts/, now parser/scripts/ - crawl-baotintuc.js wrote to /data, now data/2017 - golden tests loaded configs by their old thptqg*-data.toml names Drops the #[ignore]d Rust-vs-Node golden test. It shelled out to pnpm to run scripts/build-database.js, a file removed when the parser was ported to Rust, so it could never pass. check-duplicates.js and diff-datasets.js were already broken before this change and are annotated as such rather than half-fixed. 63 Rust tests pass and clippy is clean from the new location. --- .gitignore | 21 + 2016/.gitignore | 146 - 2016/README.md | 57 - 2016/eslint.config.js | 31 - 2016/index.html | 13 - 2016/pnpm-lock.yaml | 1624 ----------- 2016/pnpm-workspace.yaml | 2 - 2016/src/App.css | 474 --- 2016/src/App.jsx | 174 -- 2016/src/components/custom-query.jsx | 219 -- 2016/src/components/score-table.jsx | 74 - 2016/src/components/search-form.jsx | 46 - 2016/src/hooks/use-sqlite.js | 83 - 2016/src/index.css | 74 - 2016/src/main.jsx | 10 - 2016/tools/sync-from-thptqg2017.sh | 44 - 2016/vite.config.js | 7 - 2017/.gitignore | 27 - 2017/LICENSE | 201 -- 2017/README.md | 113 - 2017/index.html | 19 - 2017/package.json | 43 - 2017/pnpm-lock.yaml | 1624 ----------- 2017/pnpm-workspace.yaml | 2 - 2017/tools/xlsxread/Cargo.lock | 1159 -------- 2017/tools/xlsxread/Cargo.toml | 30 - .../xlsxread/configs/thptqg2017-data-old.toml | 75 - .../configs/thptqg2017-data-old2.toml | 76 - .../xlsxread/configs/thptqg2017-data.toml | 75 - 2017/tools/xlsxread/src/audit.rs | 174 -- 2017/tools/xlsxread/src/cli.rs | 48 - 2017/tools/xlsxread/src/config.rs | 146 - 2017/tools/xlsxread/src/error.rs | 34 - 2017/tools/xlsxread/src/lib.rs | 9 - 2017/tools/xlsxread/src/main.rs | 193 -- 2017/tools/xlsxread/src/reader.rs | 197 -- 2017/tools/xlsxread/src/transform.rs | 398 --- 2017/tools/xlsxread/src/writer.rs | 150 - 2017/tools/xlsxread/tests/fixtures/README.md | 18 - .../xlsxread/tests/fixtures/hcm-overflow.xlsx | Bin 12658 -> 0 bytes .../xlsxread/tests/fixtures/province-100.xlsx | Bin 4460 -> 0 bytes .../tests/fixtures/province-numeric-sbd.xlsx | Bin 4165 -> 0 bytes 2017/tools/xlsxread/tests/golden.rs | 690 ----- 2016/LICENSE => LICENSE | 0 ...fabb12bd9cdhyduoccantho-1468920829104.xlsx | Bin ...aef829d62968274atravinh-1468902443859.xlsx | Bin ...fa449d5ca76fae8ninhbinh-1468899778557.xlsx | Bin ...bae71aadcdbb5cninhthuan-1468920071763.xlsx | Bin ...115f77dhcnthucpham-tphcm-1468910578187.xls | Bin ...2c2b9600bc49cd3f8backan-1468933016076.xlsx | Bin ...7d0fc295fa6d2be1hagiang-1468932847230.xlsx | Bin ...c6c8be585bcb6e5cbaclieu-1468934144150.xlsx | Bin ...df237b37a7bcaeaef3hanoi-1468932790746.xlsx | Bin ...24e324d2d519e87a4daclac-1468899960505.xlsx | Bin ...806f151649ee6edhtantrao-1468901296040.xlsx | Bin ...e899b068bf98dhtaynguyen-1468940490240.xlsx | Bin ...100f93e40d5ff3bquangtri-1468933440097.xlsx | Bin ...cc6d7db4dhyduocthaibinh-1468941020145.xlsx | Bin ...089a307af23edcethanhhoa-1468933304999.xlsx | Bin ...0f2809d96be81797dhdalat-1468902130616.xlsx | Bin ...09f02d787eef2c15lamdong-1468933821082.xlsx | Bin ...95d38cfdhbachkhoa-tphcm-1468939678829.xlsx | Bin ...125a2a015714ddhdongthap-1468934545359.xlsx | Bin ...e1ff7df3ac23a15dienbien-1468920113820.xlsx | Bin ...c18bff18c2ddhthainguyen-1468940268065.xlsx | Bin ...8a0d94af5d1ed8abinhdinh-1468899884192.xlsx | Bin ...2d3bdhbachkhoa-dhdanang-1468938494437.xlsx | Bin ...341831echvkythuatquansu-1468920342994.xlsx | Bin ...42becddhcongnghieptphcm-1468983373303.xlsx | Bin ...afab309323fd22dhthuyloi-1468901840919.xlsx | Bin ...1f415238566b210khanhhoa-1468933789968.xlsx | Bin ...a94636e4d15394fc19sonla-1468899319124.xlsx | Bin ...d68e1dspkythuatvinhlong-1468902640438.xlsx | Bin ...23a6dff96ff7f9cvinhphuc-1468919874814.xlsx | Bin ...236c8dhxaydungmientrung-1468940978346.xlsx | Bin ...291e29192aebe95ehoabinh-1468983220125.xlsx | Bin ...5f02c7edhspkythuattphcm-1468906568655.xlsx | Bin ...56958bdhgiaothongvantai-1468939107463.xlsx | Bin ...573245d58fba93bcdongnai-1468938241935.xlsx | Bin ...fdhnonglam-dhthainguyen-1468939023637.xlsx | Bin ...9a48f689e2d38b85ephutho-1468902409682.xlsx | Bin ...3bd376dhsupham-dhdanang-1468938526558.xlsx | Bin ...b8f55d807324374dongthap-1468933902699.xlsx | Bin ...47a553386hvnongnghiepvn-1468900610577.xlsx | Bin ...ed0618796bae87bc3cantho-1468933954714.xlsx | Bin ...75234025dhcantho-baclieu-1468907071460.xls | Bin ...a482be08cd391thainguyen-1468902797020.xlsx | Bin ...e0608dhkhxhnv-dhqgtphcm-1468920630193.xlsx | Bin ...6dac130dhnhatrang-coso1-1468901350425.xlsx | Bin ...0db4f7c30b9735261dhvinh-1468940230027.xlsx | Bin ...d0dhkhtunhien-dhqgtphcm-1468921015146.xlsx | Bin ...183af461e945389thaibinh-1468920019273.xlsx | Bin ...672bbc39168024c9cgialai-1468933753098.xlsx | Bin ...b64f713b95fthuathienhue-1468983258438.xlsx | Bin ...9e55149a8524c5dhquynhon-1468938878328.xlsx | Bin ...bf4e40ee3e6a3ac74bentre-1468934010040.xlsx | Bin ...16a3beafa927bbdhtravinh-1468902716174.xlsx | Bin ...173af1b6ad8402kiengiang-1468900147395.xlsx | Bin ...cf56ae57283b9b9dhtaybac-1468940302052.xlsx | Bin ...f1b42a8a55dhsuphamhanoi-1468901144203.xlsx | Bin ...901fd5d68843dhhungvuong-1468901964127.xlsx | Bin ...a6342cd8f9474b22langson-1468932984587.xlsx | Bin ...37f6d161fab6f0dhxaydung-1468940561682.xlsx | Bin ...7917e920f469b90haiduong-1468899640007.xlsx | Bin ...cffdb79d724e8aecbacninh-1468919984998.xlsx | Bin ...d00aac3bcdf9974e1nghean-1468920043121.xlsx | Bin ...8bd00c2dhcantho-haugiang-1468907167921.xls | Bin ...95368e0fc11072avinhlong-1468934067981.xlsx | Bin ...66ca8adhcongnghiephanoi-1468920154757.xlsx | Bin ...6b9befd5dhnganhangtphcm-1468902244566.xlsx | Bin ...b3f33914dhkhoahoc-dhhue-1468938729472.xlsx | Bin ...dc7a8aabfdhkinhte-dhhue-1468938560205.xlsx | Bin ...congnghiep-dhthainguyen-1468901919568.xlsx | Bin ...887a7dhkinhtequocdanfix-1468902083782.xlsx | Bin ...459f8937dfcd6c7129dhhue-1468938792115.xlsx | Bin ...5b2836aa1c4bb25ahungyen-1468899732002.xlsx | Bin ...58fabb1caefba1chaugiang-1468934247324.xlsx | Bin ...92ffcacf8ff21hvtaichinh-1468934470924.xlsx | Bin ...6559eb021779daa32yenbai-1468933116055.xlsx | Bin ...1fd7dhngoaingu-dhdanang-1468902750424.xlsx | Bin ...28c3853ed53b19quangbinh-1468933376032.xlsx | Bin ...279920d4b1dhtonducthang-1468902168623.xlsx | Bin ...d7649da8b89ad90dhluathn-1468920377978.xlsx | Bin ...e32380d7558cdhsphanoi-2-1468902006284.xlsx | Bin ...7348d8c38c5b7equangninh-1468919920197.xlsx | Bin ...426deb2d5e5da5fdlaichau-1468932954079.xlsx | Bin ...d21ec95cc9ecb8fsoctrang-1468902686409.xlsx | Bin ...b2f002f0e194f7dhsptphcm-1468920792291.xlsx | Bin ...f15d42cc7dhsupham-dhhue-1468934431828.xlsx | Bin ...0dh-tai-chinh-marketing-1468924711596.xlsx | Bin ...dfbf2e278a47dhthuongmai-1468902876264.xlsx | Bin ...6372fd6e9dhnonglamtphcm-1468939555326.xlsx | Bin ...3a35cce1c6bdhbachkhoahn-1468901491486.xlsx | Bin ...740e2da5639327afdhcantho-1468907131146.xls | Bin ...d7df5f53160a851dhdanang-1468920187203.xlsx | Bin ...3a1021091a5e654bacgiang-1468983153932.xlsx | Bin ...f46445265036dhtiengiang-1468940391597.xlsx | Bin ...469ff2104527dh-hong-duc-1468900427119.xlsx | Bin ...c067a761204459f4daknong-1468934173803.xlsx | Bin ...ff38b31157bbdhmodiachat-1468900697349.xlsx | Bin ...7dhkhoahoc-dhthainguyen-1468900365545.xlsx | Bin ...fd538db5448adhgtvttphcm-1468939150821.xlsx | Bin ...6cc3bc99449ddhlamnghiep-1468939300790.xlsx | Bin ...6c1229afad4e71dhhanghai-1468906457479.xlsx | Bin ...086b86e85df54949dkontum-1468933632113.xlsx | Bin ...b67c6ef3797adhkiengiang-1468901222446.xlsx | Bin ...5785797c6ccdcb204laocai-1468919805337.xlsx | Bin ...ffad435262cb8tuyenquang-1468902296807.xlsx | Bin ...34b116f37c27dhluattphcm-1468939398928.xlsx | Bin ...421c3fb74f789c3dhsaigon-1468900867561.xlsx | Bin ...00ef10cd408d2ef0caobang-1468932877769.xlsx | Bin ...894b4e13c3ca4dhhaiphong-1468901178368.xlsx | Bin ...379ca0e9c5a1c556namdinh-1468933234061.xlsx | Bin ...916032c6a3b2fc9eedhanam-1468933146526.xlsx | Bin ...47391a0653dee5quangngai-1468933592400.xlsx | Bin ...18cd8202a5eaf0dquangnam-1468933501467.xlsx | Bin ...b493248377dhngoaithuong-1468920480753.xlsx | Bin ...f2dhsupham-dhthainguyen-1468939061872.xlsx | Bin ...41f0e98e26dhkinhtetphcm-1468939229043.xlsx | Bin ...22a1e3b4333f6hvnganhang-1468939472850.xlsx | Bin ...8a2a6dhspkythuathungyen-1468920667091.xlsx | Bin ...5f6f624445300ddhangiang-1468940189321.xlsx | Bin ...2dhkinhteluat-dhqgtphcm-1468939860894.xlsx | Bin .../2017-old}/10_BinhThuan_RIIW.xls.xlsx | Bin .../2017-old}/10_Ca_Mau_BKXT.xls.xlsx | Bin .../2017-old}/10_LamDong_GNFT.xls.xlsx | Bin .../2017-old}/10_Soc_Trang_XCGJ.xls.xlsx | Bin .../2017-old}/11_BinhDuong_RYQL.xls.xlsx | Bin .../2017-old}/11_LaoCai_GMSU.xls.xlsx | Bin .../2017-old}/12_BenTre_DKWF.xls.xlsx | Bin .../2017-old}/12_LongAn_ZZUK.xls.xlsx | Bin .../2017-old}/13_NamDinh_ESEL.xls.xlsx | Bin .../2017-old}/13_TraVinh_LKUJ.xls.xlsx | Bin .../2017-old}/14_NgheAn_BSLY.xls.xlsx | Bin .../2017-old}/15_PhuTho_ABWQ.xls.xlsx | Bin .../2017-old}/16_QuangBinh_KGEU.xls.xlsx | Bin .../2017-old}/17_QuangNam_AMTK.xls.xlsx | Bin .../2017-old}/18_QuangNgai_KOFP.xls.xlsx | Bin .../2017-old}/19_QuangTri_OMZF.xls.xlsx | Bin .../2017-old}/1_BaRia_VungTau_HJKG.xls.xlsx | Bin .../2017-old}/1_Da_Nang_AHWJ.xls.xlsx | Bin .../2017-old}/1_Ha_Noi_CVXG.xls.xlsx | Bin .../2017-old}/1_Son_La_JIDP.xls.xlsx | Bin .../2017-old}/1_TuyenQuang_JBYF.xls.xlsx | Bin .../2017-old}/20_TayNinh_ILFA.xls.xlsx | Bin .../2017-old}/21_ThaiBinh_FTVG.xls.xlsx | Bin .../2017-old}/22_ThaiNguyen_TLTW.xls.xlsx | Bin .../2017-old}/23_HaiPhong_HXBV.xls.xlsx | Bin .../2017-old}/24_HCM_XULN.xls.xlsx | Bin .../2017-old}/2_BacKan_GFVQ.xls.xlsx | Bin .../2017-old}/2_Ha_Giang_QNCM.xls.xlsx | Bin .../2017-old}/2_Ninh_Thuan_VHLY.xls.xlsx | Bin .../2017-old}/2_Thanh_Hoa_AUFV.xls.xlsx | Bin .../2017-old}/2_VinhPhuc_GUDK.xls.xlsx | Bin .../2017-old}/3_BacGiang_TOIF.xls.xlsx | Bin .../2017-old}/3_BinhPhuoc_YFMU.xls.xlsx | Bin .../2017-old}/3_Cao_Bang_CIEY.xls.xlsx | Bin .../2017-old}/3_Dong_Thap_GSXQ.xls.xlsx | Bin .../2017-old}/3_Thua_Thien_Hue_HMDB.xls.xlsx | Bin .../2017-old}/4_An_Giang_JNOS.xls.xlsx | Bin .../2017-old}/4_BacNinh_STLR.xls.xlsx | Bin .../2017-old}/4_Binh_Dinh_WWZW.xls.xlsx | Bin .../2017-old}/4_DienBien_SOJG.xls.xlsx | Bin .../2017-old}/4_Lang_Son_NYQL.xls.xlsx | Bin .../2017-old}/5_Bac_Lieu_XEKH.xls.xlsx | Bin .../2017-old}/5_Gia_Lai_ABZI.xls.xlsx | Bin .../2017-old}/5_HaiDuong_WWWG.xls.xlsx | Bin .../2017-old}/5_Hanam_QGJS.xls.xlsx | Bin .../2017-old}/5_Yen_Bai_FAQR.xls.xlsx | Bin .../2017-old}/6_Dong_Nai_WOTM.xls.xlsx | Bin .../2017-old}/6_Hau_Giang_KWDM.xls.xlsx | Bin .../2017-old}/6_HoaBinh_TPZY.xls.xlsx | Bin .../2017-old}/6_NinhBinh_IGFT.xls.xlsx | Bin .../2017-old}/6_Quang_Ninh_DQCJ.xls.xlsx | Bin .../2017-old}/7_HaTinh_DDHD.xls.xlsx | Bin .../2017-old}/7_HungYen_LTIK.xls.xlsx | Bin .../2017-old}/7_Kon_Tum_RSLR.xls.xlsx | Bin .../2017-old}/7_Tien_Giang_EFHX.xls.xlsx | Bin .../2017-old}/8_Can_Tho_RQZM.xls.xlsx | Bin .../2017-old}/8_Dak_Lak_YKPR.xls.xlsx | Bin .../2017-old}/8_KienGiang_OTOB.xls.xlsx | Bin .../2017-old}/8_PhuYen_OGIM.xls.xlsx | Bin .../2017-old}/9_DakNong_FBOP.xls.xlsx | Bin .../2017-old}/9_Khanh_Hoa_KPKQ.xls.xlsx | Bin .../2017-old}/9_LaiChau_ALKN.xls.xlsx | Bin .../2017-old}/9_Vinh_Long_OLWA.xls.xlsx | Bin .../2017-old2}/1.BaRia-VungTau_PGZT.xlsx | Bin .../2017-old2}/1.Da Nang_ABWU.xlsx | Bin .../2017-old2}/1.Son La_XLFN.xlsx | Bin .../2017-old2}/1.TuyenQuang_PTMR.xlsx | Bin .../2017-old2}/10.BinhThuan_MVVG.xlsx | Bin .../2017-old2}/10.LamDong_YUQA.xlsx | Bin .../2017-old2}/10.Soc Trang_LQWU.xlsx | Bin .../2017-old2}/11.BinhDuong_HVAH.xlsx | Bin .../2017-old2}/11.LaoCai_ZTBP.xlsx | Bin .../2017-old2}/12.BenTre_NQTU.xlsx | Bin .../2017-old2}/12.LongAn_PDRH.xlsx | Bin .../2017-old2}/13.NamDinh_NAYR.xlsx | Bin .../2017-old2}/13.TraVinh_FODZ.xlsx | Bin .../2017-old2}/14.NgheAn_HTKD.xlsx | Bin .../2017-old2}/15.PhuTho_IJZW.xlsx | Bin .../2017-old2}/17.QuangNam_NQMG.xlsx | Bin .../2017-old2}/18.QuangNgai_IUPY.xlsx | Bin .../2017-old2}/19.QuangTri_MKNN.xlsx | Bin .../2017-old2}/2.BacKan_YQNX.xlsx | Bin .../2017-old2}/2.Ha Giang_PIYK.xlsx | Bin .../2017-old2}/2.Ninh Thuan_BAGG.xlsx | Bin .../2017-old2}/2.Thanh Hoa_UOPE.xlsx | Bin .../2017-old2}/2.VinhPhuc_QZJK.xlsx | Bin .../2017-old2}/20.TayNinh_KJAQ.xlsx | Bin .../2017-old2}/21.ThaiBinh_KTQN.xlsx | Bin .../2017-old2}/22.ThaiNguyen_BKIF.xlsx | Bin .../2017-old2}/24.HCM_UTLQ.xlsx | Bin .../2017-old2}/3.BacGiang_SAVS.xlsx | Bin .../2017-old2}/3.BinhPhuoc_IPHL.xlsx | Bin .../2017-old2}/3.Cao Bang_WMUU.xlsx | Bin .../2017-old2}/3.Dong Thap_HKJX.xlsx | Bin .../2017-old2}/3.Thua Thien -Hue_MAET.xlsx | Bin .../2017-old2}/4.An Giang_PMJD.xlsx | Bin .../2017-old2}/4.BacNinh_NNIS.xlsx | Bin .../2017-old2}/4.Binh Dinh_VOMJ.xlsx | Bin .../2017-old2}/4.DienBien_FYGN.xlsx | Bin .../2017-old2}/4.Lang Son_QWOG.xlsx | Bin .../2017-old2}/5.Bac Lieu_VIVY.xlsx | Bin .../2017-old2}/5.Gia Lai_TAAS.xlsx | Bin .../2017-old2}/5.HaiDuong_WNHD.xlsx | Bin .../2017-old2}/5.Hanam_SDKN.xlsx | Bin .../2017-old2}/5.Yen Bai_BSLV.xlsx | Bin .../2017-old2}/6.Hau Giang_SIAJ.xlsx | Bin .../2017-old2}/6.HoaBinh_HLYQ.xlsx | Bin .../2017-old2}/6.NinhBinh_PKMQ.xlsx | Bin .../2017-old2}/6.Quang Ninh_YAKJ.xlsx | Bin .../2017-old2}/7.HaTinh_XMFQ.xlsx | Bin .../2017-old2}/7.HungYen_TCBE.xlsx | Bin .../2017-old2}/7.Kon Tum_CAQU.xlsx | Bin .../2017-old2}/7.Tien Giang_AOWZ.xlsx | Bin .../2017-old2}/8.PhuYen_MLTQ.xlsx | Bin .../2017-old2}/9.DakNong_ZWJT.xlsx | Bin .../2017-old2}/9.Khanh Hoa_IBTX.xlsx | Bin .../2017-old2}/9.Vinh Long_WVKI.xlsx | Bin {2017/data => data/2017}/an-giang.xls | Bin {2017/data => data/2017}/ba-ria-vung-tau.xls | Bin {2017/data => data/2017}/bac-giang.xls | Bin {2017/data => data/2017}/bac-kan.xls | Bin {2017/data => data/2017}/bac-lieu.xls | Bin {2017/data => data/2017}/bac-ninh.xls | Bin {2017/data => data/2017}/ben-tre.xls | Bin {2017/data => data/2017}/binh-dinh.xls | Bin {2017/data => data/2017}/binh-duong.xls | Bin {2017/data => data/2017}/binh-phuoc.xls | Bin {2017/data => data/2017}/binh-thuan.xls | Bin {2017/data => data/2017}/ca-mau.xls | Bin {2017/data => data/2017}/can-tho.xls | Bin {2017/data => data/2017}/cao-bang.xls | Bin {2017/data => data/2017}/da-nang.xls | Bin {2017/data => data/2017}/dak-lak.xls | Bin {2017/data => data/2017}/dak-nong.xls | Bin {2017/data => data/2017}/dien-bien.xls | Bin {2017/data => data/2017}/dong-nai.xls | Bin {2017/data => data/2017}/dong-thap.xls | Bin {2017/data => data/2017}/gia-lai.xls | Bin {2017/data => data/2017}/ha-giang.xls | Bin {2017/data => data/2017}/ha-nam.xls | Bin {2017/data => data/2017}/ha-noi.xls | Bin {2017/data => data/2017}/ha-tinh.xls | Bin {2017/data => data/2017}/hai-duong.xls | Bin {2017/data => data/2017}/hai-phong.xls | Bin {2017/data => data/2017}/hau-giang.xls | Bin {2017/data => data/2017}/ho-chi-minh.xls | Bin {2017/data => data/2017}/hoa-binh.xls | Bin {2017/data => data/2017}/hung-yen.xls | Bin {2017/data => data/2017}/khanh-hoa.xls | Bin {2017/data => data/2017}/kien-giang.xls | Bin {2017/data => data/2017}/kon-tum.xls | Bin {2017/data => data/2017}/lai-chau.xls | Bin {2017/data => data/2017}/lam-dong.xls | Bin {2017/data => data/2017}/lang-son.xls | Bin {2017/data => data/2017}/lao-cai.xls | Bin {2017/data => data/2017}/long-an.xls | Bin {2017/data => data/2017}/nam-dinh.xls | Bin {2017/data => data/2017}/nghe-an.xls | Bin {2017/data => data/2017}/ninh-binh.xls | Bin {2017/data => data/2017}/ninh-thuan.xls | Bin {2017/data => data/2017}/phu-tho.xls | Bin {2017/data => data/2017}/phu-yen.xls | Bin {2017/data => data/2017}/quang-binh.xls | Bin {2017/data => data/2017}/quang-nam.xls | Bin {2017/data => data/2017}/quang-ngai.xls | Bin {2017/data => data/2017}/quang-ninh.xls | Bin {2017/data => data/2017}/quang-tri.xls | Bin {2017/data => data/2017}/soc-trang.xls | Bin {2017/data => data/2017}/son-la.xls | Bin {2017/data => data/2017}/tay-ninh.xls | Bin {2017/data => data/2017}/thai-binh.xls | Bin {2017/data => data/2017}/thai-nguyen.xls | Bin {2017/data => data/2017}/thanh-hoa.xls | Bin {2017/data => data/2017}/thua-thien-hue.xls | Bin {2017/data => data/2017}/tien-giang.xls | Bin {2017/data => data/2017}/tra-vinh.xls | Bin {2017/data => data/2017}/tuyen-quang.xls | Bin {2017/data => data/2017}/vinh-long.xls | Bin {2017/data => data/2017}/vinh-phuc.xls | Bin {2017/data => data/2017}/yen-bai.xls | Bin {2017/docs => docs}/README.md | 0 .../codebase-summary-2016-legacy.md | 0 {2017/docs => docs}/data-pipeline.md | 0 .../deployment-guide-2016-legacy.md | 0 {2017/docs => docs}/deployment-guide.md | 0 .../project-overview-pdr-2016-legacy.md | 0 .../system-architecture-2016-legacy.md | 0 {2017/docs => docs}/system-architecture.md | 0 2017/eslint.config.js => eslint.config.js | 6 +- index.html | 39 +- package-lock.json | 2569 +++++++++++++++++ 2016/package.json => package.json | 11 +- {2016/tools/xlsxread => parser}/Cargo.lock | 0 {2016/tools/xlsxread => parser}/Cargo.toml | 0 .../configs/2016.toml | 0 .../configs/2017-old.toml | 0 .../configs/2017-old2.toml | 0 .../configs/2017.toml | 0 parser/scripts/build-db.js | 66 + {2017 => parser}/scripts/check-duplicates.js | 6 +- {2017 => parser}/scripts/crawl-baotintuc.js | 4 +- {2017 => parser}/scripts/db-stats.js | 0 {2017 => parser}/scripts/diff-datasets.js | 9 +- {2017 => parser}/scripts/verify-parity.js | 0 {2016/tools/xlsxread => parser}/src/audit.rs | 0 {2016/tools/xlsxread => parser}/src/cli.rs | 0 {2016/tools/xlsxread => parser}/src/config.rs | 0 {2016/tools/xlsxread => parser}/src/error.rs | 0 .../src/format_detect_2016.rs | 0 {2016/tools/xlsxread => parser}/src/lib.rs | 0 {2016/tools/xlsxread => parser}/src/main.rs | 0 {2016/tools/xlsxread => parser}/src/reader.rs | 0 {2016/tools/xlsxread => parser}/src/schema.rs | 0 .../xlsxread => parser}/src/transform.rs | 0 {2016/tools/xlsxread => parser}/src/writer.rs | 0 .../tests/fixtures/README.md | 0 .../tests/fixtures/hcm-overflow.xlsx | Bin .../tests/fixtures/province-100.xlsx | Bin .../tests/fixtures/province-numeric-sbd.xlsx | Bin .../tools/xlsxread => parser}/tests/golden.rs | 116 +- {2017/src => src}/App.css | 0 {2017/src => src}/App.jsx | 0 {2017/src => src}/assets/vite.svg | 0 {2017/src => src}/components/custom-query.jsx | 0 {2017/src => src}/components/score-table.jsx | 0 {2017/src => src}/components/search-form.jsx | 0 .../src => src}/components/student-detail.jsx | 0 src/datasets.js | 47 + {2017/src => src}/hooks/use-sqlite.js | 0 {2017/src => src}/index.css | 0 {2017/src => src}/lib/admission-blocks.js | 0 {2017/src => src}/main.jsx | 0 2017/vite.config.js => vite.config.js | 0 396 files changed, 2753 insertions(+), 8720 deletions(-) create mode 100644 .gitignore delete mode 100644 2016/.gitignore delete mode 100644 2016/README.md delete mode 100644 2016/eslint.config.js delete mode 100644 2016/index.html delete mode 100644 2016/pnpm-lock.yaml delete mode 100644 2016/pnpm-workspace.yaml delete mode 100644 2016/src/App.css delete mode 100644 2016/src/App.jsx delete mode 100644 2016/src/components/custom-query.jsx delete mode 100644 2016/src/components/score-table.jsx delete mode 100644 2016/src/components/search-form.jsx delete mode 100644 2016/src/hooks/use-sqlite.js delete mode 100644 2016/src/index.css delete mode 100644 2016/src/main.jsx delete mode 100755 2016/tools/sync-from-thptqg2017.sh delete mode 100644 2016/vite.config.js delete mode 100644 2017/.gitignore delete mode 100644 2017/LICENSE delete mode 100644 2017/README.md delete mode 100644 2017/index.html delete mode 100644 2017/package.json delete mode 100644 2017/pnpm-lock.yaml delete mode 100644 2017/pnpm-workspace.yaml delete mode 100644 2017/tools/xlsxread/Cargo.lock delete mode 100644 2017/tools/xlsxread/Cargo.toml delete mode 100644 2017/tools/xlsxread/configs/thptqg2017-data-old.toml delete mode 100644 2017/tools/xlsxread/configs/thptqg2017-data-old2.toml delete mode 100644 2017/tools/xlsxread/configs/thptqg2017-data.toml delete mode 100644 2017/tools/xlsxread/src/audit.rs delete mode 100644 2017/tools/xlsxread/src/cli.rs delete mode 100644 2017/tools/xlsxread/src/config.rs delete mode 100644 2017/tools/xlsxread/src/error.rs delete mode 100644 2017/tools/xlsxread/src/lib.rs delete mode 100644 2017/tools/xlsxread/src/main.rs delete mode 100644 2017/tools/xlsxread/src/reader.rs delete mode 100644 2017/tools/xlsxread/src/transform.rs delete mode 100644 2017/tools/xlsxread/src/writer.rs delete mode 100644 2017/tools/xlsxread/tests/fixtures/README.md delete mode 100644 2017/tools/xlsxread/tests/fixtures/hcm-overflow.xlsx delete mode 100644 2017/tools/xlsxread/tests/fixtures/province-100.xlsx delete mode 100644 2017/tools/xlsxread/tests/fixtures/province-numeric-sbd.xlsx delete mode 100644 2017/tools/xlsxread/tests/golden.rs rename 2016/LICENSE => LICENSE (100%) rename {2016/data => data/2016}/023718c7d3cf7ace3a7116fabb12bd9cdhyduoccantho-1468920829104.xlsx (100%) rename {2016/data => data/2016}/08cdeb3636dcb2adaef829d62968274atravinh-1468902443859.xlsx (100%) rename {2016/data => data/2016}/0b583c9875443e65ffa449d5ca76fae8ninhbinh-1468899778557.xlsx (100%) rename {2016/data => data/2016}/15c85d901a73dd49f2bae71aadcdbb5cninhthuan-1468920071763.xlsx (100%) rename {2016/data => data/2016}/167116af6c8a096c2a9307edfa115f77dhcnthucpham-tphcm-1468910578187.xls (100%) rename {2016/data => data/2016}/17843bccde10f362c2b9600bc49cd3f8backan-1468933016076.xlsx (100%) rename {2016/data => data/2016}/178814c33c8b85a77d0fc295fa6d2be1hagiang-1468932847230.xlsx (100%) rename {2016/data => data/2016}/18055d17e46854ecc6c8be585bcb6e5cbaclieu-1468934144150.xlsx (100%) rename {2016/data => data/2016}/1c66db0265bf45df237b37a7bcaeaef3hanoi-1468932790746.xlsx (100%) rename {2016/data => data/2016}/2004a8d225fd87524e324d2d519e87a4daclac-1468899960505.xlsx (100%) rename {2016/data => data/2016}/20db5eaace927596f1806f151649ee6edhtantrao-1468901296040.xlsx (100%) rename {2016/data => data/2016}/216ee4e385dbc236767be899b068bf98dhtaynguyen-1468940490240.xlsx (100%) rename {2016/data => data/2016}/2208903e1fa12220d100f93e40d5ff3bquangtri-1468933440097.xlsx (100%) rename {2016/data => data/2016}/22e8617886412abd90ae3d33cc6d7db4dhyduocthaibinh-1468941020145.xlsx (100%) rename {2016/data => data/2016}/238adc19e80c0daef089a307af23edcethanhhoa-1468933304999.xlsx (100%) rename {2016/data => data/2016}/2b33640b0dd154490f2809d96be81797dhdalat-1468902130616.xlsx (100%) rename {2016/data => data/2016}/2fa6d9a308bd11bc09f02d787eef2c15lamdong-1468933821082.xlsx (100%) rename {2016/data => data/2016}/357c6aaf59aeaa6c11c3e83c595d38cfdhbachkhoa-tphcm-1468939678829.xlsx (100%) rename {2016/data => data/2016}/388fcdfdac18ef6eee6125a2a015714ddhdongthap-1468934545359.xlsx (100%) rename {2016/data => data/2016}/3c0e56abd8c5334f4e1ff7df3ac23a15dienbien-1468920113820.xlsx (100%) rename {2016/data => data/2016}/3daa6ee33fdafadc3c112c18bff18c2ddhthainguyen-1468940268065.xlsx (100%) rename {2016/data => data/2016}/412e62265f35ca0078a0d94af5d1ed8abinhdinh-1468899884192.xlsx (100%) rename {2016/data => data/2016}/43213f61074068d9177685eb6c3f2d3bdhbachkhoa-dhdanang-1468938494437.xlsx (100%) rename {2016/data => data/2016}/4334ea476a2b8196d54ba40a341831echvkythuatquansu-1468920342994.xlsx (100%) rename {2016/data => data/2016}/487c7287c1c9735722b31d877942becddhcongnghieptphcm-1468983373303.xlsx (100%) rename {2016/data => data/2016}/4a3fa95a83fe9b3b2fafab309323fd22dhthuyloi-1468901840919.xlsx (100%) rename {2016/data => data/2016}/4ad416ccf014bd5d01f415238566b210khanhhoa-1468933789968.xlsx (100%) rename {2016/data => data/2016}/4b98fdd7300b86a94636e4d15394fc19sonla-1468899319124.xlsx (100%) rename {2016/data => data/2016}/4c2fd846ed2a0670ba6d1200d1d68e1dspkythuatvinhlong-1468902640438.xlsx (100%) rename {2016/data => data/2016}/4e0ccee19eb64513d23a6dff96ff7f9cvinhphuc-1468919874814.xlsx (100%) rename {2016/data => data/2016}/4e9bb192d56c9fa92b3e0ec13d8236c8dhxaydungmientrung-1468940978346.xlsx (100%) rename {2016/data => data/2016}/505a876dfd1ea321291e29192aebe95ehoabinh-1468983220125.xlsx (100%) rename {2016/data => data/2016}/514877c1cfebdc9c2251f651b5f02c7edhspkythuattphcm-1468906568655.xlsx (100%) rename {2016/data => data/2016}/51bb2f9b6e9f565c2d705606fd56958bdhgiaothongvantai-1468939107463.xlsx (100%) rename {2016/data => data/2016}/538c9676b70f2509573245d58fba93bcdongnai-1468938241935.xlsx (100%) rename {2016/data => data/2016}/53e5e20ebd74d84741513b703fbd13bfdhnonglam-dhthainguyen-1468939023637.xlsx (100%) rename {2016/data => data/2016}/5465cca59495dcd9a48f689e2d38b85ephutho-1468902409682.xlsx (100%) rename {2016/data => data/2016}/54bbcf865c137d58cf62af15733bd376dhsupham-dhdanang-1468938526558.xlsx (100%) rename {2016/data => data/2016}/575df8a4df74e87abb8f55d807324374dongthap-1468933902699.xlsx (100%) rename {2016/data => data/2016}/5aede4951e7af8c1e1056c747a553386hvnongnghiepvn-1468900610577.xlsx (100%) rename {2016/data => data/2016}/5b16d7156a03bb7ed0618796bae87bc3cantho-1468933954714.xlsx (100%) rename {2016/data => data/2016}/5ca241aa1de8d25a3e6ff6db75234025dhcantho-baclieu-1468907071460.xls (100%) rename {2016/data => data/2016}/5fb3a1b66aff077ee3da482be08cd391thainguyen-1468902797020.xlsx (100%) rename {2016/data => data/2016}/5fd13ae5287cbf0149bd733b507e0608dhkhxhnv-dhqgtphcm-1468920630193.xlsx (100%) rename {2016/data => data/2016}/6375fd13557bee08d20f1f3e46dac130dhnhatrang-coso1-1468901350425.xlsx (100%) rename {2016/data => data/2016}/64d2635efd30a0d0db4f7c30b9735261dhvinh-1468940230027.xlsx (100%) rename {2016/data => data/2016}/64e44466ffeff9a587260795644805d0dhkhtunhien-dhqgtphcm-1468921015146.xlsx (100%) rename {2016/data => data/2016}/6960b6fa493e1365a183af461e945389thaibinh-1468920019273.xlsx (100%) rename {2016/data => data/2016}/698b930ab7697a0672bbc39168024c9cgialai-1468933753098.xlsx (100%) rename {2016/data => data/2016}/6badc7cfa258b59ad67e2b64f713b95fthuathienhue-1468983258438.xlsx (100%) rename {2016/data => data/2016}/70bf8cd2b6e87523219e55149a8524c5dhquynhon-1468938878328.xlsx (100%) rename {2016/data => data/2016}/74145979ee30186bf4e40ee3e6a3ac74bentre-1468934010040.xlsx (100%) rename {2016/data => data/2016}/7418e83ff9d07b146216a3beafa927bbdhtravinh-1468902716174.xlsx (100%) rename {2016/data => data/2016}/7435bb054e8e4ec34c173af1b6ad8402kiengiang-1468900147395.xlsx (100%) rename {2016/data => data/2016}/74e6cd0dc78a3fb7dcf56ae57283b9b9dhtaybac-1468940302052.xlsx (100%) rename {2016/data => data/2016}/76f19098881e9c79f66ac4f1b42a8a55dhsuphamhanoi-1468901144203.xlsx (100%) rename {2016/data => data/2016}/778ab074ed6a95d209fa901fd5d68843dhhungvuong-1468901964127.xlsx (100%) rename {2016/data => data/2016}/7afd5d7fdff7c170a6342cd8f9474b22langson-1468932984587.xlsx (100%) rename {2016/data => data/2016}/7b5d74564ab9f6e0e137f6d161fab6f0dhxaydung-1468940561682.xlsx (100%) rename {2016/data => data/2016}/7cfc91bd6a1f5ae9d7917e920f469b90haiduong-1468899640007.xlsx (100%) rename {2016/data => data/2016}/7e0d0b6fb981d407cffdb79d724e8aecbacninh-1468919984998.xlsx (100%) rename {2016/data => data/2016}/7f12b90225e91f9d00aac3bcdf9974e1nghean-1468920043121.xlsx (100%) rename {2016/data => data/2016}/7f1cbe7f35d1f539ca817a0ab8bd00c2dhcantho-haugiang-1468907167921.xls (100%) rename {2016/data => data/2016}/7f4362ef567cdf74495368e0fc11072avinhlong-1468934067981.xlsx (100%) rename {2016/data => data/2016}/82338a4a93ea1e0cde26e0061066ca8adhcongnghiephanoi-1468920154757.xlsx (100%) rename {2016/data => data/2016}/86a692bebf9b0b7c58adb9876b9befd5dhnganhangtphcm-1468902244566.xlsx (100%) rename {2016/data => data/2016}/87ffaf3197ba20f0919f98a0b3f33914dhkhoahoc-dhhue-1468938729472.xlsx (100%) rename {2016/data => data/2016}/8916da7b3c4d58cffc1dd29dc7a8aabfdhkinhte-dhhue-1468938560205.xlsx (100%) rename {2016/data => data/2016}/8af8f1b29b6a40e26ccb4a2e19e8eededhkythuatcongnghiep-dhthainguyen-1468901919568.xlsx (100%) rename {2016/data => data/2016}/8f948c2a5ab49a3c5fd03b6ea04887a7dhkinhtequocdanfix-1468902083782.xlsx (100%) rename {2016/data => data/2016}/919276a0348634459f8937dfcd6c7129dhhue-1468938792115.xlsx (100%) rename {2016/data => data/2016}/92045214159cb0335b2836aa1c4bb25ahungyen-1468899732002.xlsx (100%) rename {2016/data => data/2016}/964c4368131f6be6058fabb1caefba1chaugiang-1468934247324.xlsx (100%) rename {2016/data => data/2016}/96c95c85c5549a06f2e92ffcacf8ff21hvtaichinh-1468934470924.xlsx (100%) rename {2016/data => data/2016}/97aa741a4c2b1276559eb021779daa32yenbai-1468933116055.xlsx (100%) rename {2016/data => data/2016}/9ba098a7913ad837a66e173b3fc41fd7dhngoaingu-dhdanang-1468902750424.xlsx (100%) rename {2016/data => data/2016}/9c730c43bf4309171528c3853ed53b19quangbinh-1468933376032.xlsx (100%) rename {2016/data => data/2016}/9d78f6dce7965fb4b7a337279920d4b1dhtonducthang-1468902168623.xlsx (100%) rename {2016/data => data/2016}/9e0e564ae801e347bd7649da8b89ad90dhluathn-1468920377978.xlsx (100%) rename {2016/data => data/2016}/a11e707e6ed5fe4d29a8e32380d7558cdhsphanoi-2-1468902006284.xlsx (100%) rename {2016/data => data/2016}/a31b3446bae5a17c517348d8c38c5b7equangninh-1468919920197.xlsx (100%) rename {2016/data => data/2016}/a3aa106104f114c6426deb2d5e5da5fdlaichau-1468932954079.xlsx (100%) rename {2016/data => data/2016}/a8ff80d9478747e36d21ec95cc9ecb8fsoctrang-1468902686409.xlsx (100%) rename {2016/data => data/2016}/a995de3f7a7055cf10b2f002f0e194f7dhsptphcm-1468920792291.xlsx (100%) rename {2016/data => data/2016}/ab2f259ef55cb08b3a436d3f15d42cc7dhsupham-dhhue-1468934431828.xlsx (100%) rename {2016/data => data/2016}/af6828f837a80e03d77a65f3d310ec60dh-tai-chinh-marketing-1468924711596.xlsx (100%) rename {2016/data => data/2016}/b2552e20c9ff4b237244dfbf2e278a47dhthuongmai-1468902876264.xlsx (100%) rename {2016/data => data/2016}/b2a739584a8861502573d1c6372fd6e9dhnonglamtphcm-1468939555326.xlsx (100%) rename {2016/data => data/2016}/b34c777942ca8a4de91f23a35cce1c6bdhbachkhoahn-1468901491486.xlsx (100%) rename {2016/data => data/2016}/b35a3f26a162bec3740e2da5639327afdhcantho-1468907131146.xls (100%) rename {2016/data => data/2016}/b42fd58ead4c54279d7df5f53160a851dhdanang-1468920187203.xlsx (100%) rename {2016/data => data/2016}/b7a0c1ecce7c8445b3a1021091a5e654bacgiang-1468983153932.xlsx (100%) rename {2016/data => data/2016}/bacd1b2133b37d0ea9fbf46445265036dhtiengiang-1468940391597.xlsx (100%) rename {2016/data => data/2016}/bd857add0cfe92c1c247469ff2104527dh-hong-duc-1468900427119.xlsx (100%) rename {2016/data => data/2016}/bf259a908ff8a8dcc067a761204459f4daknong-1468934173803.xlsx (100%) rename {2016/data => data/2016}/c174631d90303276ac63ff38b31157bbdhmodiachat-1468900697349.xlsx (100%) rename {2016/data => data/2016}/c2cfaaf287fb1e7120894e545771b027dhkhoahoc-dhthainguyen-1468900365545.xlsx (100%) rename {2016/data => data/2016}/c5c28959fcd0b4e39dd9fd538db5448adhgtvttphcm-1468939150821.xlsx (100%) rename {2016/data => data/2016}/c5ecc58a731fd1a54b7e6cc3bc99449ddhlamnghiep-1468939300790.xlsx (100%) rename {2016/data => data/2016}/c6ef16bc9f75ce0fd16c1229afad4e71dhhanghai-1468906457479.xlsx (100%) rename {2016/data => data/2016}/cc57dc986acb525086b86e85df54949dkontum-1468933632113.xlsx (100%) rename {2016/data => data/2016}/cdc912664d7217c75eb9b67c6ef3797adhkiengiang-1468901222446.xlsx (100%) rename {2016/data => data/2016}/d035f470c13adbf5785797c6ccdcb204laocai-1468919805337.xlsx (100%) rename {2016/data => data/2016}/d5ecd2574b5ab36c62dffad435262cb8tuyenquang-1468902296807.xlsx (100%) rename {2016/data => data/2016}/d652d24e8bd4fe6a48d634b116f37c27dhluattphcm-1468939398928.xlsx (100%) rename {2016/data => data/2016}/d75282bff0a4d8cd1421c3fb74f789c3dhsaigon-1468900867561.xlsx (100%) rename {2016/data => data/2016}/ddb631f833af894200ef10cd408d2ef0caobang-1468932877769.xlsx (100%) rename {2016/data => data/2016}/deca197a916a8f633f6894b4e13c3ca4dhhaiphong-1468901178368.xlsx (100%) rename {2016/data => data/2016}/dfa63c5b68a8f638379ca0e9c5a1c556namdinh-1468933234061.xlsx (100%) rename {2016/data => data/2016}/e693bc9de67acc916032c6a3b2fc9eedhanam-1468933146526.xlsx (100%) rename {2016/data => data/2016}/e80dc028d53fa49ee247391a0653dee5quangngai-1468933592400.xlsx (100%) rename {2016/data => data/2016}/ec765c32190773f5a18cd8202a5eaf0dquangnam-1468933501467.xlsx (100%) rename {2016/data => data/2016}/ec84067268f47d523b1e80b493248377dhngoaithuong-1468920480753.xlsx (100%) rename {2016/data => data/2016}/ee09c723da4e86cdbe26213413450af2dhsupham-dhthainguyen-1468939061872.xlsx (100%) rename {2016/data => data/2016}/f0aa5a19c2c8c1fde8211341f0e98e26dhkinhtetphcm-1468939229043.xlsx (100%) rename {2016/data => data/2016}/f2846894bd5533e02b122a1e3b4333f6hvnganhang-1468939472850.xlsx (100%) rename {2016/data => data/2016}/f85f04bb2bbd84457b83ac846728a2a6dhspkythuathungyen-1468920667091.xlsx (100%) rename {2016/data => data/2016}/fc511852659150f6305f6f624445300ddhangiang-1468940189321.xlsx (100%) rename {2016/data => data/2016}/ff877788e43bd84f0119dae026996892dhkinhteluat-dhqgtphcm-1468939860894.xlsx (100%) rename {2017/data-old => data/2017-old}/10_BinhThuan_RIIW.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/10_Ca_Mau_BKXT.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/10_LamDong_GNFT.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/10_Soc_Trang_XCGJ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/11_BinhDuong_RYQL.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/11_LaoCai_GMSU.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/12_BenTre_DKWF.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/12_LongAn_ZZUK.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/13_NamDinh_ESEL.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/13_TraVinh_LKUJ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/14_NgheAn_BSLY.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/15_PhuTho_ABWQ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/16_QuangBinh_KGEU.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/17_QuangNam_AMTK.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/18_QuangNgai_KOFP.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/19_QuangTri_OMZF.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/1_BaRia_VungTau_HJKG.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/1_Da_Nang_AHWJ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/1_Ha_Noi_CVXG.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/1_Son_La_JIDP.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/1_TuyenQuang_JBYF.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/20_TayNinh_ILFA.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/21_ThaiBinh_FTVG.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/22_ThaiNguyen_TLTW.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/23_HaiPhong_HXBV.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/24_HCM_XULN.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/2_BacKan_GFVQ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/2_Ha_Giang_QNCM.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/2_Ninh_Thuan_VHLY.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/2_Thanh_Hoa_AUFV.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/2_VinhPhuc_GUDK.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/3_BacGiang_TOIF.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/3_BinhPhuoc_YFMU.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/3_Cao_Bang_CIEY.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/3_Dong_Thap_GSXQ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/3_Thua_Thien_Hue_HMDB.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/4_An_Giang_JNOS.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/4_BacNinh_STLR.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/4_Binh_Dinh_WWZW.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/4_DienBien_SOJG.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/4_Lang_Son_NYQL.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/5_Bac_Lieu_XEKH.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/5_Gia_Lai_ABZI.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/5_HaiDuong_WWWG.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/5_Hanam_QGJS.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/5_Yen_Bai_FAQR.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/6_Dong_Nai_WOTM.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/6_Hau_Giang_KWDM.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/6_HoaBinh_TPZY.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/6_NinhBinh_IGFT.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/6_Quang_Ninh_DQCJ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/7_HaTinh_DDHD.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/7_HungYen_LTIK.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/7_Kon_Tum_RSLR.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/7_Tien_Giang_EFHX.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/8_Can_Tho_RQZM.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/8_Dak_Lak_YKPR.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/8_KienGiang_OTOB.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/8_PhuYen_OGIM.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/9_DakNong_FBOP.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/9_Khanh_Hoa_KPKQ.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/9_LaiChau_ALKN.xls.xlsx (100%) rename {2017/data-old => data/2017-old}/9_Vinh_Long_OLWA.xls.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/1.BaRia-VungTau_PGZT.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/1.Da Nang_ABWU.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/1.Son La_XLFN.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/1.TuyenQuang_PTMR.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/10.BinhThuan_MVVG.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/10.LamDong_YUQA.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/10.Soc Trang_LQWU.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/11.BinhDuong_HVAH.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/11.LaoCai_ZTBP.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/12.BenTre_NQTU.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/12.LongAn_PDRH.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/13.NamDinh_NAYR.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/13.TraVinh_FODZ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/14.NgheAn_HTKD.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/15.PhuTho_IJZW.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/17.QuangNam_NQMG.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/18.QuangNgai_IUPY.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/19.QuangTri_MKNN.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/2.BacKan_YQNX.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/2.Ha Giang_PIYK.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/2.Ninh Thuan_BAGG.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/2.Thanh Hoa_UOPE.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/2.VinhPhuc_QZJK.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/20.TayNinh_KJAQ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/21.ThaiBinh_KTQN.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/22.ThaiNguyen_BKIF.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/24.HCM_UTLQ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/3.BacGiang_SAVS.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/3.BinhPhuoc_IPHL.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/3.Cao Bang_WMUU.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/3.Dong Thap_HKJX.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/3.Thua Thien -Hue_MAET.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/4.An Giang_PMJD.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/4.BacNinh_NNIS.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/4.Binh Dinh_VOMJ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/4.DienBien_FYGN.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/4.Lang Son_QWOG.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/5.Bac Lieu_VIVY.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/5.Gia Lai_TAAS.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/5.HaiDuong_WNHD.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/5.Hanam_SDKN.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/5.Yen Bai_BSLV.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/6.Hau Giang_SIAJ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/6.HoaBinh_HLYQ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/6.NinhBinh_PKMQ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/6.Quang Ninh_YAKJ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/7.HaTinh_XMFQ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/7.HungYen_TCBE.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/7.Kon Tum_CAQU.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/7.Tien Giang_AOWZ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/8.PhuYen_MLTQ.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/9.DakNong_ZWJT.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/9.Khanh Hoa_IBTX.xlsx (100%) rename {2017/data-old2 => data/2017-old2}/9.Vinh Long_WVKI.xlsx (100%) rename {2017/data => data/2017}/an-giang.xls (100%) rename {2017/data => data/2017}/ba-ria-vung-tau.xls (100%) rename {2017/data => data/2017}/bac-giang.xls (100%) rename {2017/data => data/2017}/bac-kan.xls (100%) rename {2017/data => data/2017}/bac-lieu.xls (100%) rename {2017/data => data/2017}/bac-ninh.xls (100%) rename {2017/data => data/2017}/ben-tre.xls (100%) rename {2017/data => data/2017}/binh-dinh.xls (100%) rename {2017/data => data/2017}/binh-duong.xls (100%) rename {2017/data => data/2017}/binh-phuoc.xls (100%) rename {2017/data => data/2017}/binh-thuan.xls (100%) rename {2017/data => data/2017}/ca-mau.xls (100%) rename {2017/data => data/2017}/can-tho.xls (100%) rename {2017/data => data/2017}/cao-bang.xls (100%) rename {2017/data => data/2017}/da-nang.xls (100%) rename {2017/data => data/2017}/dak-lak.xls (100%) rename {2017/data => data/2017}/dak-nong.xls (100%) rename {2017/data => data/2017}/dien-bien.xls (100%) rename {2017/data => data/2017}/dong-nai.xls (100%) rename {2017/data => data/2017}/dong-thap.xls (100%) rename {2017/data => data/2017}/gia-lai.xls (100%) rename {2017/data => data/2017}/ha-giang.xls (100%) rename {2017/data => data/2017}/ha-nam.xls (100%) rename {2017/data => data/2017}/ha-noi.xls (100%) rename {2017/data => data/2017}/ha-tinh.xls (100%) rename {2017/data => data/2017}/hai-duong.xls (100%) rename {2017/data => data/2017}/hai-phong.xls (100%) rename {2017/data => data/2017}/hau-giang.xls (100%) rename {2017/data => data/2017}/ho-chi-minh.xls (100%) rename {2017/data => data/2017}/hoa-binh.xls (100%) rename {2017/data => data/2017}/hung-yen.xls (100%) rename {2017/data => data/2017}/khanh-hoa.xls (100%) rename {2017/data => data/2017}/kien-giang.xls (100%) rename {2017/data => data/2017}/kon-tum.xls (100%) rename {2017/data => data/2017}/lai-chau.xls (100%) rename {2017/data => data/2017}/lam-dong.xls (100%) rename {2017/data => data/2017}/lang-son.xls (100%) rename {2017/data => data/2017}/lao-cai.xls (100%) rename {2017/data => data/2017}/long-an.xls (100%) rename {2017/data => data/2017}/nam-dinh.xls (100%) rename {2017/data => data/2017}/nghe-an.xls (100%) rename {2017/data => data/2017}/ninh-binh.xls (100%) rename {2017/data => data/2017}/ninh-thuan.xls (100%) rename {2017/data => data/2017}/phu-tho.xls (100%) rename {2017/data => data/2017}/phu-yen.xls (100%) rename {2017/data => data/2017}/quang-binh.xls (100%) rename {2017/data => data/2017}/quang-nam.xls (100%) rename {2017/data => data/2017}/quang-ngai.xls (100%) rename {2017/data => data/2017}/quang-ninh.xls (100%) rename {2017/data => data/2017}/quang-tri.xls (100%) rename {2017/data => data/2017}/soc-trang.xls (100%) rename {2017/data => data/2017}/son-la.xls (100%) rename {2017/data => data/2017}/tay-ninh.xls (100%) rename {2017/data => data/2017}/thai-binh.xls (100%) rename {2017/data => data/2017}/thai-nguyen.xls (100%) rename {2017/data => data/2017}/thanh-hoa.xls (100%) rename {2017/data => data/2017}/thua-thien-hue.xls (100%) rename {2017/data => data/2017}/tien-giang.xls (100%) rename {2017/data => data/2017}/tra-vinh.xls (100%) rename {2017/data => data/2017}/tuyen-quang.xls (100%) rename {2017/data => data/2017}/vinh-long.xls (100%) rename {2017/data => data/2017}/vinh-phuc.xls (100%) rename {2017/data => data/2017}/yen-bai.xls (100%) rename {2017/docs => docs}/README.md (100%) rename 2016/docs/codebase-summary.md => docs/codebase-summary-2016-legacy.md (100%) rename {2017/docs => docs}/data-pipeline.md (100%) rename 2016/docs/deployment-guide.md => docs/deployment-guide-2016-legacy.md (100%) rename {2017/docs => docs}/deployment-guide.md (100%) rename 2016/docs/project-overview-pdr.md => docs/project-overview-pdr-2016-legacy.md (100%) rename 2016/docs/system-architecture.md => docs/system-architecture-2016-legacy.md (100%) rename {2017/docs => docs}/system-architecture.md (100%) rename 2017/eslint.config.js => eslint.config.js (82%) create mode 100644 package-lock.json rename 2016/package.json => package.json (55%) rename {2016/tools/xlsxread => parser}/Cargo.lock (100%) rename {2016/tools/xlsxread => parser}/Cargo.toml (100%) rename 2016/tools/xlsxread/configs/thptqg2016-data.toml => parser/configs/2016.toml (100%) rename 2016/tools/xlsxread/configs/thptqg2017-data-old.toml => parser/configs/2017-old.toml (100%) rename 2016/tools/xlsxread/configs/thptqg2017-data-old2.toml => parser/configs/2017-old2.toml (100%) rename 2016/tools/xlsxread/configs/thptqg2017-data.toml => parser/configs/2017.toml (100%) create mode 100644 parser/scripts/build-db.js rename {2017 => parser}/scripts/check-duplicates.js (74%) rename {2017 => parser}/scripts/crawl-baotintuc.js (97%) rename {2017 => parser}/scripts/db-stats.js (100%) rename {2017 => parser}/scripts/diff-datasets.js (90%) rename {2017 => parser}/scripts/verify-parity.js (100%) rename {2016/tools/xlsxread => parser}/src/audit.rs (100%) rename {2016/tools/xlsxread => parser}/src/cli.rs (100%) rename {2016/tools/xlsxread => parser}/src/config.rs (100%) rename {2016/tools/xlsxread => parser}/src/error.rs (100%) rename {2016/tools/xlsxread => parser}/src/format_detect_2016.rs (100%) rename {2016/tools/xlsxread => parser}/src/lib.rs (100%) rename {2016/tools/xlsxread => parser}/src/main.rs (100%) rename {2016/tools/xlsxread => parser}/src/reader.rs (100%) rename {2016/tools/xlsxread => parser}/src/schema.rs (100%) rename {2016/tools/xlsxread => parser}/src/transform.rs (100%) rename {2016/tools/xlsxread => parser}/src/writer.rs (100%) rename {2016/tools/xlsxread => parser}/tests/fixtures/README.md (100%) rename {2016/tools/xlsxread => parser}/tests/fixtures/hcm-overflow.xlsx (100%) rename {2016/tools/xlsxread => parser}/tests/fixtures/province-100.xlsx (100%) rename {2016/tools/xlsxread => parser}/tests/fixtures/province-numeric-sbd.xlsx (100%) rename {2016/tools/xlsxread => parser}/tests/golden.rs (83%) rename {2017/src => src}/App.css (100%) rename {2017/src => src}/App.jsx (100%) rename {2017/src => src}/assets/vite.svg (100%) rename {2017/src => src}/components/custom-query.jsx (100%) rename {2017/src => src}/components/score-table.jsx (100%) rename {2017/src => src}/components/search-form.jsx (100%) rename {2017/src => src}/components/student-detail.jsx (100%) create mode 100644 src/datasets.js rename {2017/src => src}/hooks/use-sqlite.js (100%) rename {2017/src => src}/index.css (100%) rename {2017/src => src}/lib/admission-blocks.js (100%) rename {2017/src => src}/main.jsx (100%) rename 2017/vite.config.js => vite.config.js (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..22c54aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +### Editors ### +.idea +*.iws +*.iml +*.ipr +.vscode/ + +### Mac OS ### +.DS_Store + +### Node ### +node_modules/ + +### Build output ### +dist/ + +### Generated databases and Vite publicDir staging ### +.build/ + +### Rust build artefacts ### +parser/target/ diff --git a/2016/.gitignore b/2016/.gitignore deleted file mode 100644 index 051b283..0000000 --- a/2016/.gitignore +++ /dev/null @@ -1,146 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.* -!.env.example - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Sveltekit cache directory -.svelte-kit/ - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# Firebase cache directory -.firebase/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v3 -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -# Vite logs files -vite.config.js.timestamp-* -vite.config.ts.timestamp-* - -# Generated database files -public/*.db -public/*.db.gz - -# Rust build artifacts -tools/xlsxread/target/ diff --git a/2016/README.md b/2016/README.md deleted file mode 100644 index a086341..0000000 --- a/2016/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# thptqg2016 - -Lookup tool for Vietnam's 2016 National High School Graduation Exam (THPT Quốc gia) scores — 877,461 candidates nationwide. - -Fully static app running entirely in the browser (SQLite via `sql.js`). No backend, no query logging. - -## Features - -- **Quick lookup** by exam ID (`số báo danh`) or full name (diacritics-insensitive) -- **Custom read-only SQL** (SELECT / PRAGMA / EXPLAIN / WITH) with 7 built-in preset queries -- **Complete data**: 12 subjects (Math, Literature, Physics, Chemistry, Biology, History, Geography, English, French, German, Japanese, Chinese), exam cluster, date of birth, gender -- Safety caps: 100 rows for lookup, 1000 rows for custom SQL -- Dark mode, `Ctrl+Enter` shortcut to run queries - -## Demo - - - -## Development - -```bash -# Build the SQLite database from source Excel files (requires Rust stable) -pnpm run build:db - -# Or build in two steps: -pnpm run build:rust # compile the xlsxread binary -./tools/xlsxread/target/release/xlsxread build \ - --schema tools/xlsxread/configs/thptqg2016-data.toml \ - --input data \ - --output public/thptqg2016.db - -pnpm run dev # Vite dev server -pnpm run build # Production bundle → dist/ -pnpm run lint # ESLint -``` - -The database is built by the `xlsxread` Rust binary (`tools/xlsxread/`), which -reads the 119 mixed `.xls`/`.xlsx` files and auto-detects the column layout per -file (`separate-scores`, `mapped`, or positional default). No Node.js Excel -library is required at build time. - -The GitHub Actions workflow (`.github/workflows/deploy.yml`) compiles -`xlsxread`, builds the DB, gzips it, and deploys to GitHub Pages on every push -to `main`. - -## Tech stack - -React 19 · Vite · sql.js (WASM) · xlsxread (Rust, build-time) · GitHub Pages - -## Documentation - -- [Project overview (PDR)](./docs/project-overview-pdr.md) -- [Codebase summary](./docs/codebase-summary.md) -- [System architecture](./docs/system-architecture.md) -- [Deployment guide](./docs/deployment-guide.md) - -**Source**: Originally published at (currently inaccessible). Data is for reference only. diff --git a/2016/eslint.config.js b/2016/eslint.config.js deleted file mode 100644 index 1f236de..0000000 --- a/2016/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; - -export default [ - { ignores: ["dist"] }, - { - files: ["**/*.{js,jsx}"], - languageOptions: { - ecmaVersion: 2024, - globals: globals.browser, - parserOptions: { - ecmaVersion: "latest", - ecmaFeatures: { jsx: true }, - sourceType: "module", - }, - }, - plugins: { - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": [ - "warn", - { allowConstantExport: true }, - ], - }, - }, -]; diff --git a/2016/index.html b/2016/index.html deleted file mode 100644 index 172159e..0000000 --- a/2016/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Tra cứu điểm thi THPT QG 2016 - - -
- - - diff --git a/2016/pnpm-lock.yaml b/2016/pnpm-lock.yaml deleted file mode 100644 index ce02b86..0000000 --- a/2016/pnpm-lock.yaml +++ /dev/null @@ -1,1624 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - react: - specifier: ^19.2.4 - version: 19.2.6 - react-dom: - specifier: ^19.2.4 - version: 19.2.6(react@19.2.6) - sql.js: - specifier: ^1.14.1 - version: 1.14.1 - devDependencies: - '@eslint/js': - specifier: ^9.39.4 - version: 9.39.4 - '@types/react': - specifier: ^19.2.14 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.14) - '@vitejs/plugin-react': - specifier: ^6.0.1 - version: 6.0.1(vite@8.0.16) - eslint: - specifier: ^9.39.4 - version: 9.39.4 - eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.1.1(eslint@9.39.4) - eslint-plugin-react-refresh: - specifier: ^0.5.2 - version: 0.5.2(eslint@9.39.4) - globals: - specifier: ^17.4.0 - version: 17.6.0 - vite: - specifier: ^8.0.16 - version: 8.0.16 - -packages: - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} - engines: {node: '>=18.18.0'} - - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@napi-rs/wasm-runtime@1.1.6': - resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} - - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-rc.7': - resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} - - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - - '@tybys/wasm-util@0.10.3': - resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - - '@vitejs/plugin-react@6.0.1': - resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 - babel-plugin-react-compiler: ^1.0.0 - vite: ^8.0.0 - peerDependenciesMeta: - '@rolldown/plugin-babel': - optional: true - babel-plugin-react-compiler: - optional: true - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - baseline-browser-mapping@2.10.29: - resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001792: - resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - electron-to-chromium@1.5.353: - resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-plugin-react-hooks@7.1.1: - resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - - eslint-plugin-react-refresh@0.5.2: - resolution: {integrity: sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==} - peerDependencies: - eslint: ^9 || ^10 - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@17.6.0: - resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==} - engines: {node: '>=18'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lightningcss-android-arm64@1.33.0: - resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.33.0: - resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.33.0: - resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.33.0: - resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.33.0: - resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.33.0: - resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.33.0: - resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.33.0: - resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.33.0: - resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.33.0: - resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.33.0: - resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.33.0: - resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} - engines: {node: '>= 12.0.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - node-releases@2.0.38: - resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.5: - resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} - engines: {node: '>=12'} - - postcss@8.5.23: - resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - react-dom@19.2.6: - resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} - peerDependencies: - react: ^19.2.6 - - react@19.2.6: - resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} - engines: {node: '>=0.10.0'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - sql.js@1.14.1: - resolution: {integrity: sha512-gcj8zBWU5cFsi9WUP+4bFNXAyF1iRpA3LLyS/DP5xlrNzGmPIizUeBggKa8DbDwdqaKwUcTEnChtd2grWo/x/A==} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - tinyglobby@0.2.17: - resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} - engines: {node: '>=12.0.0'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - vite@8.0.16: - resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 - esbuild: ^0.27.0 || ^0.28.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - -snapshots: - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.3': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)': - dependencies: - eslint: 9.39.4 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 - - '@humanfs/node@0.16.8': - dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 - '@humanwhocodes/retry': 0.4.3 - - '@humanfs/types@0.15.0': {} - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.3 - optional: true - - '@oxc-project/types@0.133.0': {} - - '@rolldown/binding-android-arm64@1.0.3': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.3': - optional: true - - '@rolldown/binding-darwin-x64@1.0.3': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.3': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.3': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.3': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.3': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.3': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.3': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.0.3': - optional: true - - '@rolldown/pluginutils@1.0.0-rc.7': {} - - '@rolldown/pluginutils@1.0.1': {} - - '@tybys/wasm-util@0.10.3': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/estree@1.0.9': {} - - '@types/json-schema@7.0.15': {} - - '@types/react-dom@19.2.3(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - - '@vitejs/plugin-react@6.0.1(vite@8.0.16)': - dependencies: - '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.16 - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - argparse@2.0.1: {} - - balanced-match@1.0.2: {} - - baseline-browser-mapping@2.10.29: {} - - brace-expansion@1.1.14: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - browserslist@4.28.2: - dependencies: - baseline-browser-mapping: 2.10.29 - caniuse-lite: 1.0.30001792 - electron-to-chromium: 1.5.353 - node-releases: 2.0.38 - update-browserslist-db: 1.2.3(browserslist@4.28.2) - - callsites@3.1.0: {} - - caniuse-lite@1.0.30001792: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - concat-map@0.0.1: {} - - convert-source-map@2.0.0: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.2.3: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - detect-libc@2.1.2: {} - - electron-to-chromium@1.5.353: {} - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-plugin-react-hooks@7.1.1(eslint@9.39.4): - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - eslint: 9.39.4 - hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-refresh@0.5.2(eslint@9.39.4): - dependencies: - eslint: 9.39.4 - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint@9.39.4: - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fdir@6.5.0(picomatch@4.0.5): - optionalDependencies: - picomatch: 4.0.5 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - fsevents@2.3.3: - optional: true - - gensync@1.0.0-beta.2: {} - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - globals@14.0.0: {} - - globals@17.6.0: {} - - has-flag@4.0.0: {} - - hermes-estree@0.25.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - ignore@5.3.2: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - isexe@2.0.0: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lightningcss-android-arm64@1.33.0: - optional: true - - lightningcss-darwin-arm64@1.33.0: - optional: true - - lightningcss-darwin-x64@1.33.0: - optional: true - - lightningcss-freebsd-x64@1.33.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.33.0: - optional: true - - lightningcss-linux-arm64-gnu@1.33.0: - optional: true - - lightningcss-linux-arm64-musl@1.33.0: - optional: true - - lightningcss-linux-x64-gnu@1.33.0: - optional: true - - lightningcss-linux-x64-musl@1.33.0: - optional: true - - lightningcss-win32-arm64-msvc@1.33.0: - optional: true - - lightningcss-win32-x64-msvc@1.33.0: - optional: true - - lightningcss@1.33.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.33.0 - lightningcss-darwin-arm64: 1.33.0 - lightningcss-darwin-x64: 1.33.0 - lightningcss-freebsd-x64: 1.33.0 - lightningcss-linux-arm-gnueabihf: 1.33.0 - lightningcss-linux-arm64-gnu: 1.33.0 - lightningcss-linux-arm64-musl: 1.33.0 - lightningcss-linux-x64-gnu: 1.33.0 - lightningcss-linux-x64-musl: 1.33.0 - lightningcss-win32-arm64-msvc: 1.33.0 - lightningcss-win32-x64-msvc: 1.33.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 - - ms@2.1.3: {} - - nanoid@3.3.16: {} - - natural-compare@1.4.0: {} - - node-releases@2.0.38: {} - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - picocolors@1.1.1: {} - - picomatch@4.0.5: {} - - postcss@8.5.23: - dependencies: - nanoid: 3.3.16 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - punycode@2.3.1: {} - - react-dom@19.2.6(react@19.2.6): - dependencies: - react: 19.2.6 - scheduler: 0.27.0 - - react@19.2.6: {} - - resolve-from@4.0.0: {} - - rolldown@1.0.3: - dependencies: - '@oxc-project/types': 0.133.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 - - scheduler@0.27.0: {} - - semver@6.3.1: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - source-map-js@1.2.1: {} - - sql.js@1.14.1: {} - - strip-json-comments@3.1.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - tinyglobby@0.2.17: - dependencies: - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 - - tslib@2.8.1: - optional: true - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - vite@8.0.16: - dependencies: - lightningcss: 1.33.0 - picomatch: 4.0.5 - postcss: 8.5.23 - rolldown: 1.0.3 - tinyglobby: 0.2.17 - optionalDependencies: - fsevents: 2.3.3 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - yallist@3.1.1: {} - - yocto-queue@0.1.0: {} - - zod-validation-error@4.0.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - - zod@4.4.3: {} diff --git a/2016/pnpm-workspace.yaml b/2016/pnpm-workspace.yaml deleted file mode 100644 index 65783dc..0000000 --- a/2016/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -allowBuilds: - better-sqlite3: true diff --git a/2016/src/App.css b/2016/src/App.css deleted file mode 100644 index 9410c19..0000000 --- a/2016/src/App.css +++ /dev/null @@ -1,474 +0,0 @@ -.app { - max-width: 1200px; - margin: 0 auto; - padding: 2rem 1rem 3rem; -} - -/* Header */ -header { - text-align: center; - margin-bottom: 2rem; -} - -header h1 { - font-size: clamp(1.4rem, 2.4vw, 2rem); - color: var(--text); - margin: 0 0 0.4rem; - letter-spacing: -0.01em; - font-weight: 700; -} - -.subtitle { - color: var(--text-muted); - font-size: 0.95rem; - margin: 0; -} - -.subtitle .pill { - display: inline-block; - padding: 0.1rem 0.55rem; - background: var(--accent-soft); - color: var(--accent); - border-radius: 999px; - font-weight: 600; - font-size: 0.8rem; - margin-right: 0.35rem; -} - -/* Tabs */ -.tabs { - display: flex; - gap: 0; - max-width: 600px; - margin: 0 auto 1.5rem; - border-bottom: 1px solid var(--border); -} - -.tab { - flex: 1; - padding: 0.75rem 1rem; - font-size: 0.95rem; - background: none; - border: none; - border-bottom: 2px solid transparent; - margin-bottom: -1px; - cursor: pointer; - color: var(--text-muted); - font-weight: 500; - transition: color 0.15s, border-color 0.15s; -} - -.tab:hover { - color: var(--accent); -} - -.tab[aria-selected="true"] { - color: var(--accent); - border-bottom-color: var(--accent); - font-weight: 600; -} - -/* Search form */ -.search-form { - display: flex; - gap: 0.5rem; - max-width: 600px; - margin: 0 auto 1.5rem; - position: relative; -} - -.search-field { - flex: 1; - position: relative; -} - -.search-form input { - width: 100%; - padding: 0.75rem 2.25rem 0.75rem 1rem; - font-size: 1rem; - border: 1px solid var(--border-strong); - border-radius: var(--radius); - background: var(--surface); - color: var(--text); - outline: none; - transition: border-color 0.15s, box-shadow 0.15s; -} - -.search-form input:focus { - border-color: var(--accent); - box-shadow: 0 0 0 3px var(--accent-soft); -} - -.search-clear { - position: absolute; - right: 0.4rem; - top: 50%; - transform: translateY(-50%); - width: 1.75rem; - height: 1.75rem; - display: grid; - place-items: center; - border: none; - background: transparent; - color: var(--text-faint); - font-size: 1.1rem; - border-radius: 50%; - cursor: pointer; -} - -.search-clear:hover { - background: var(--surface-alt); - color: var(--text); -} - -.search-form button[type="submit"] { - padding: 0.75rem 1.5rem; - font-size: 0.95rem; - font-weight: 600; - background: var(--accent); - color: #fff; - border: none; - border-radius: var(--radius); - cursor: pointer; - transition: background 0.15s, transform 0.05s; -} - -.search-form button[type="submit"]:hover:not(:disabled) { - background: var(--accent-hover); -} - -.search-form button[type="submit"]:active:not(:disabled) { - transform: translateY(1px); -} - -.search-form button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -/* Custom query */ -.custom-query { - max-width: 960px; - margin: 0 auto; -} - -.preset-list { - display: flex; - flex-wrap: wrap; - gap: 0.4rem; - margin-bottom: 0.85rem; - align-items: center; -} - -.preset-label { - font-size: 0.8rem; - color: var(--text-muted); - white-space: nowrap; - margin-right: 0.25rem; - font-weight: 500; -} - -.preset-btn { - padding: 0.35rem 0.75rem; - font-size: 0.8rem; - background: var(--surface); - border: 1px solid var(--border); - color: var(--text); - border-radius: 999px; - cursor: pointer; - transition: background 0.15s, border-color 0.15s, color 0.15s; -} - -.preset-btn:hover:not(:disabled) { - background: var(--accent-soft); - border-color: var(--accent); - color: var(--accent); -} - -.preset-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.query-form { - margin-bottom: 1rem; -} - -.query-form textarea { - width: 100%; - padding: 0.85rem 1rem; - font-size: 0.9rem; - font-family: - "JetBrains Mono", "Cascadia Code", "Fira Code", ui-monospace, monospace; - background: var(--surface); - color: var(--text); - border: 1px solid var(--border-strong); - border-radius: var(--radius); - outline: none; - resize: vertical; - min-height: 130px; - transition: border-color 0.15s, box-shadow 0.15s; - tab-size: 2; - line-height: 1.5; -} - -.query-form textarea:focus { - border-color: var(--accent); - box-shadow: 0 0 0 3px var(--accent-soft); -} - -.query-actions { - display: flex; - align-items: center; - gap: 1rem; - margin-top: 0.6rem; - flex-wrap: wrap; -} - -.query-actions button { - padding: 0.6rem 1.4rem; - font-size: 0.9rem; - font-weight: 600; - background: var(--accent); - color: #fff; - border: none; - border-radius: var(--radius); - cursor: pointer; - transition: background 0.15s; -} - -.query-actions button:hover:not(:disabled) { - background: var(--accent-hover); -} - -.query-actions button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.exec-time { - font-size: 0.85rem; - color: var(--text-muted); - font-variant-numeric: tabular-nums; -} - -.exec-time.running { - color: var(--accent); -} - -.kbd { - display: inline-block; - padding: 0.05rem 0.4rem; - font-family: ui-monospace, monospace; - font-size: 0.75rem; - background: var(--surface-alt); - border: 1px solid var(--border); - border-bottom-width: 2px; - border-radius: 4px; - color: var(--text-muted); -} - -/* Loading */ -.loading { - max-width: 600px; - margin: 0.5rem auto 1.5rem; - padding: 0.85rem 1rem; - text-align: center; - color: var(--text-muted); - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); -} - -.loading p { - margin: 0 0 0.5rem; - font-size: 0.9rem; -} - -.progress-bar { - width: 100%; - max-width: 300px; - height: 6px; - background: var(--surface-alt); - border-radius: 4px; - margin: 0 auto; - overflow: hidden; -} - -.progress-fill { - height: 100%; - background: linear-gradient(90deg, var(--accent), var(--accent-hover)); - border-radius: 4px; - transition: width 0.3s; -} - -/* Results table */ -.table-wrapper { - overflow-x: auto; - margin-top: 1rem; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); -} - -.result-count { - color: var(--text-muted); - font-size: 0.9rem; - margin: 0.5rem 0; - padding: 0 0.25rem; -} - -table { - width: 100%; - border-collapse: collapse; - font-size: 0.9rem; -} - -thead th { - background: var(--surface-alt); - padding: 0.65rem 0.6rem; - text-align: left; - white-space: nowrap; - position: sticky; - top: 0; - border-bottom: 1px solid var(--border-strong); - color: var(--text-muted); - font-weight: 600; - font-size: 0.8rem; - text-transform: uppercase; - letter-spacing: 0.03em; -} - -tbody td { - padding: 0.55rem 0.6rem; - border-bottom: 1px solid var(--border); -} - -tbody tr:last-child td { - border-bottom: none; -} - -tbody tr:nth-child(even) td { - background: color-mix(in srgb, var(--surface-alt) 45%, transparent); -} - -tbody tr:hover td { - background: var(--accent-soft); -} - -.sbd-cell { - font-family: ui-monospace, monospace; - font-size: 0.85rem; - color: var(--text-muted); - white-space: nowrap; -} - -.name-cell { - white-space: nowrap; - font-weight: 500; -} - -.cumthi-cell { - font-size: 0.82rem; - color: var(--text-muted); - max-width: 220px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.score-cell { - text-align: center; - font-variant-numeric: tabular-nums; -} - -.score-cell.score-high { - color: var(--ok); - font-weight: 600; -} - -.score-cell.score-low { - color: var(--danger); -} - -.score-cell.score-empty { - color: var(--text-faint); -} - -/* Messages */ -.no-results, -.error, -.warning { - text-align: center; - padding: 0.9rem 1rem; - border-radius: var(--radius); - margin: 1rem auto; - max-width: 600px; - font-size: 0.9rem; -} - -.no-results { - color: var(--text-muted); - background: var(--surface); - border: 1px dashed var(--border-strong); -} - -.error { - color: var(--danger); - background: var(--danger-bg); - border: 1px solid color-mix(in srgb, var(--danger) 25%, transparent); -} - -.warning { - color: var(--warn); - background: var(--warn-bg); -} - -/* Footer */ -footer { - text-align: center; - margin-top: 3rem; - padding-top: 1rem; - border-top: 1px solid var(--border); - color: var(--text-faint); - font-size: 0.85rem; -} - -footer a { - color: var(--text-muted); -} - -/* Responsive */ -@media (max-width: 640px) { - .app { - padding: 1.25rem 0.75rem 2rem; - } - - .search-form { - flex-direction: column; - } - - .search-form button[type="submit"] { - width: 100%; - } - - table { - font-size: 0.8rem; - } - - thead th, - tbody td { - padding: 0.45rem 0.4rem; - } - - .preset-list { - flex-direction: column; - align-items: stretch; - } - - .preset-btn { - text-align: left; - } -} diff --git a/2016/src/App.jsx b/2016/src/App.jsx deleted file mode 100644 index 494519c..0000000 --- a/2016/src/App.jsx +++ /dev/null @@ -1,174 +0,0 @@ -import { useState, useCallback, useEffect } from "react"; -import { useSqlite } from "./hooks/use-sqlite"; -import { SearchForm } from "./components/search-form"; -import { ScoreTable } from "./components/score-table"; -import { CustomQuery } from "./components/custom-query"; -import "./App.css"; - -const DB_URL = import.meta.env.BASE_URL + "thptqg2016.db.gz"; -const MAX_RESULTS = 100; - -// Strip Vietnamese diacritics for search: "nguyễn bữu lộc" → "nguyen buu loc" -function toAscii(str) { - return str - .normalize("NFD") - .replace(/[\u0300-\u036f]/g, "") - .replace(/đ/gi, "d") - .toLowerCase(); -} - -// Check if string contains only ASCII (no Vietnamese diacritics) -function isAsciiOnly(str) { - return /^[\x00-\x7F]*$/.test(str); -} - -function App() { - const { db, loading, error, progress } = useSqlite(DB_URL); - const [results, setResults] = useState(null); - const [searchError, setSearchError] = useState(null); - const [activeTab, setActiveTab] = useState("search"); - - const handleSearch = useCallback( - (query) => { - if (!db) return; - setSearchError(null); - - try { - const isExamId = /^[A-Z]{2,4}\d+$/i.test(query) || /^\d+$/.test(query); - let stmt; - - if (isExamId) { - stmt = db.prepare( - "SELECT * FROM student WHERE so_bao_danh = $q LIMIT $limit", - ); - stmt.bind({ $q: query.toUpperCase(), $limit: MAX_RESULTS }); - } else if (isAsciiOnly(query)) { - // ASCII input: search against normalized column (diacritics-insensitive) - stmt = db.prepare( - "SELECT * FROM student WHERE ho_ten_ascii LIKE $q LIMIT $limit", - ); - stmt.bind({ $q: `%${toAscii(query)}%`, $limit: MAX_RESULTS }); - } else { - // Vietnamese input: search both original and normalized - const normalized = toAscii(query); - stmt = db.prepare( - `SELECT * FROM student - WHERE ho_ten LIKE $q OR ho_ten_ascii LIKE $qn - LIMIT $limit`, - ); - stmt.bind({ - $q: `%${query}%`, - $qn: `%${normalized}%`, - $limit: MAX_RESULTS, - }); - } - - const rows = []; - while (stmt.step()) { - rows.push(stmt.getAsObject()); - } - stmt.free(); - setResults(rows); - } catch (err) { - setSearchError(err.message); - } - }, - [db], - ); - - // Ctrl+Enter shortcut to execute query in SQL tab - useEffect(() => { - function handleKeyDown(e) { - if (e.ctrlKey && e.key === "Enter" && activeTab === "sql") { - const form = document.querySelector(".query-form"); - if (form) form.requestSubmit(); - } - } - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [activeTab]); - - return ( -
-
-

Tra cứu điểm thi THPT Quốc gia 2016

-

- 877.461 thí sinh - Dữ liệu toàn quốc · Hỗ trợ truy vấn SQL tùy chỉnh -

-
- -
- {loading && ( -
-

- Đang tải cơ sở dữ liệu{progress > 0 ? ` · ${progress}%` : "..."} -

-
-
-
-
- )} - - {error &&

Lỗi: {error}

} - -
- - -
- - {activeTab === "search" && ( - <> - - - {searchError && ( -

Lỗi truy vấn: {searchError}

- )} - - - - {results && results.length >= MAX_RESULTS && ( -

- Hiển thị tối đa {MAX_RESULTS} kết quả. Vui lòng tìm kiếm cụ - thể hơn. -

- )} - - )} - - {activeTab === "sql" && ( - - )} -
- -
-

- Nguồn: Sưu tầm từ trang báo thời đó · Dữ liệu chỉ mang tính tham - khảo -

-
-
- ); -} - -export default App; diff --git a/2016/src/components/custom-query.jsx b/2016/src/components/custom-query.jsx deleted file mode 100644 index 5b4ed01..0000000 --- a/2016/src/components/custom-query.jsx +++ /dev/null @@ -1,219 +0,0 @@ -import { useState, useCallback } from "react"; - -const MAX_ROWS = 1000; - -const PRESET_QUERIES = [ - { - label: "Top 10 điểm Toán cao nhất", - sql: `SELECT so_bao_danh, ho_ten, ten_cum_thi, toan -FROM student WHERE toan IS NOT NULL -ORDER BY toan DESC LIMIT 10`, - }, - { - label: "Điểm trung bình theo cụm thi", - sql: `SELECT ten_cum_thi, - COUNT(*) AS so_luong, - ROUND(AVG(toan), 2) AS tb_toan, - ROUND(AVG(ngu_van), 2) AS tb_van, - ROUND(AVG(tieng_anh), 2) AS tb_anh -FROM student -GROUP BY ten_cum_thi -ORDER BY so_luong DESC -LIMIT 20`, - }, - { - label: "Thống kê theo giới tính", - sql: `SELECT gioi_tinh, - COUNT(*) AS so_luong, - ROUND(AVG(toan), 2) AS tb_toan, - ROUND(AVG(ngu_van), 2) AS tb_van -FROM student -WHERE gioi_tinh IS NOT NULL -GROUP BY gioi_tinh`, - }, - { - label: "Thí sinh đạt 9+ điểm Toán", - sql: `SELECT so_bao_danh, ho_ten, ten_cum_thi, gioi_tinh, toan -FROM student WHERE toan >= 9 -ORDER BY toan DESC LIMIT 50`, - }, - { - label: "Phân bố điểm Toán", - sql: `SELECT - CASE - WHEN toan < 1 THEN '0-1' - WHEN toan < 2 THEN '1-2' - WHEN toan < 3 THEN '2-3' - WHEN toan < 4 THEN '3-4' - WHEN toan < 5 THEN '4-5' - WHEN toan < 6 THEN '5-6' - WHEN toan < 7 THEN '6-7' - WHEN toan < 8 THEN '7-8' - WHEN toan < 9 THEN '8-9' - ELSE '9-10' - END AS khoang_diem, - COUNT(*) AS so_luong -FROM student WHERE toan IS NOT NULL -GROUP BY khoang_diem -ORDER BY khoang_diem`, - }, - { - label: "Số thí sinh theo ngoại ngữ", - sql: `SELECT - SUM(CASE WHEN tieng_anh IS NOT NULL THEN 1 ELSE 0 END) AS tieng_anh, - SUM(CASE WHEN tieng_phap IS NOT NULL THEN 1 ELSE 0 END) AS tieng_phap, - SUM(CASE WHEN tieng_duc IS NOT NULL THEN 1 ELSE 0 END) AS tieng_duc, - SUM(CASE WHEN tieng_nhat IS NOT NULL THEN 1 ELSE 0 END) AS tieng_nhat, - SUM(CASE WHEN tieng_trung IS NOT NULL THEN 1 ELSE 0 END) AS tieng_trung -FROM student`, - }, - { - label: "Schema bảng student", - sql: `PRAGMA table_info(student)`, - }, -]; - -export function CustomQuery({ db, disabled }) { - const [sql, setSql] = useState(""); - const [columns, setColumns] = useState([]); - const [rows, setRows] = useState([]); - const [queryError, setQueryError] = useState(null); - const [execTime, setExecTime] = useState(null); - - const executeQuery = useCallback( - (queryStr) => { - if (!db) return; - setQueryError(null); - setColumns([]); - setRows([]); - setExecTime(null); - - const trimmed = queryStr.trim(); - if (!trimmed) return; - - // Safety: only allow read-only statements - const upper = trimmed.toUpperCase(); - const allowed = ["SELECT", "PRAGMA", "EXPLAIN", "WITH"]; - if (!allowed.some((kw) => upper.startsWith(kw))) { - setQueryError( - "Chỉ hỗ trợ truy vấn đọc (SELECT, PRAGMA, EXPLAIN, WITH).", - ); - return; - } - - // Auto-add LIMIT if user forgot - let finalSql = trimmed; - if ( - upper.startsWith("SELECT") && - !upper.includes("LIMIT") && - !upper.includes("PRAGMA") - ) { - finalSql = `${trimmed.replace(/;$/, "")} LIMIT ${MAX_ROWS}`; - } - - try { - const start = performance.now(); - const stmt = db.prepare(finalSql); - const colNames = stmt.getColumnNames(); - const resultRows = []; - - let count = 0; - while (stmt.step() && count < MAX_ROWS) { - resultRows.push(stmt.get()); - count++; - } - stmt.free(); - - const elapsed = performance.now() - start; - setColumns(colNames); - setRows(resultRows); - setExecTime(elapsed.toFixed(1)); - } catch (err) { - setQueryError(err.message); - } - }, - [db], - ); - - function handleSubmit(e) { - e.preventDefault(); - executeQuery(sql); - } - - function handlePreset(presetSql) { - setSql(presetSql); - executeQuery(presetSql); - } - - return ( -
-
- Mẫu truy vấn: - {PRESET_QUERIES.map((p, i) => ( - - ))} -
- -
-